mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #1626 from sharelatex/pr-history-drag-and-drop-selection
History drag and drop selection GitOrigin-RevId: d2bc0dfc2e2634553224b7bef2ac5d926d42bf01
This commit is contained in:
parent
ca9e6044c8
commit
9c5c6922b9
20 changed files with 843 additions and 472 deletions
|
@ -162,6 +162,9 @@ block requirejs
|
||||||
"ace/keybinding-vim": {
|
"ace/keybinding-vim": {
|
||||||
"deps": ["ace/ace"]
|
"deps": ["ace/ace"]
|
||||||
},
|
},
|
||||||
|
"libs/jquery.ui.touch-punch": {
|
||||||
|
"deps": [ "libs/#{lib('jquery-layout')}" ]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"config":{
|
"config":{
|
||||||
"moment":{
|
"moment":{
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
aside.change-list(
|
aside.change-list(
|
||||||
ng-if="history.isV2 && history.viewMode === HistoryViewModes.POINT_IN_TIME"
|
ng-if="history.isV2"
|
||||||
ng-controller="HistoryV2ListController"
|
ng-controller="HistoryV2ListController"
|
||||||
)
|
)
|
||||||
history-entries-list(
|
history-entries-list(
|
||||||
ng-if="!history.showOnlyLabels && !history.error"
|
ng-if="!history.showOnlyLabels && !history.error"
|
||||||
entries="history.updates"
|
entries="history.updates"
|
||||||
|
range-selection-enabled="history.viewMode === HistoryViewModes.COMPARE"
|
||||||
selected-history-version="history.selection.range.toV"
|
selected-history-version="history.selection.range.toV"
|
||||||
|
selected-history-range="history.selection.range"
|
||||||
current-user="user"
|
current-user="user"
|
||||||
current-user-is-owner="project.owner._id === user.id"
|
current-user-is-owner="project.owner._id === user.id"
|
||||||
users="projectUsers"
|
users="projectUsers"
|
||||||
|
@ -14,232 +16,23 @@ aside.change-list(
|
||||||
load-initialize="ui.view == 'history'"
|
load-initialize="ui.view == 'history'"
|
||||||
is-loading="history.loading"
|
is-loading="history.loading"
|
||||||
free-history-limit-hit="history.freeHistoryLimitHit"
|
free-history-limit-hit="history.freeHistoryLimitHit"
|
||||||
on-entry-select="handleEntrySelect(selectedEntry)"
|
on-version-select="handleVersionSelect(version)"
|
||||||
|
on-range-select="handleRangeSelect(selectedToV, selectedFromV)"
|
||||||
on-label-delete="handleLabelDelete(label)"
|
on-label-delete="handleLabelDelete(label)"
|
||||||
)
|
)
|
||||||
history-labels-list(
|
history-labels-list(
|
||||||
ng-if="history.showOnlyLabels && !history.error"
|
ng-if="history.showOnlyLabels && !history.error"
|
||||||
labels="history.labels"
|
labels="history.labels"
|
||||||
|
range-selection-enabled="history.viewMode === HistoryViewModes.COMPARE"
|
||||||
|
selected-history-version="history.selection.range.toV"
|
||||||
|
selected-history-range="history.selection.range"
|
||||||
current-user="user"
|
current-user="user"
|
||||||
users="projectUsers"
|
users="projectUsers"
|
||||||
is-loading="history.loading"
|
is-loading="history.loading"
|
||||||
selected-label="history.selection.label"
|
on-version-select="handleVersionSelect(version)"
|
||||||
on-label-select="handleLabelSelect(label)"
|
on-range-select="handleRangeSelect(selectedToV, selectedFromV)"
|
||||||
on-label-delete="handleLabelDelete(label)"
|
on-label-delete="handleLabelDelete(label)"
|
||||||
)
|
)
|
||||||
aside.change-list.change-list-compare(
|
|
||||||
ng-if="history.isV2 && history.viewMode === HistoryViewModes.COMPARE"
|
|
||||||
ng-controller="HistoryCompareController"
|
|
||||||
)
|
|
||||||
div(
|
|
||||||
ng-if="!history.showOnlyLabels && !history.error"
|
|
||||||
)
|
|
||||||
aside.change-list(
|
|
||||||
infinite-scroll="loadMore()"
|
|
||||||
infinite-scroll-disabled="history.loading || history.atEnd"
|
|
||||||
infinite-scroll-initialize="ui.view == 'history' && history.viewMode === HistoryViewModes.COMPARE"
|
|
||||||
)
|
|
||||||
.infinite-scroll-inner
|
|
||||||
ul.list-unstyled(
|
|
||||||
ng-class="{\
|
|
||||||
'hover-state': history.hoveringOverListSelectors\
|
|
||||||
}"
|
|
||||||
)
|
|
||||||
li.change(
|
|
||||||
ng-repeat="update in history.updates track by update.fromV"
|
|
||||||
ng-class="{\
|
|
||||||
'first-in-day': update.meta.first_in_day,\
|
|
||||||
'selected': update.toV <= history.selection.range.toV && update.fromV >= history.selection.range.fromV,\
|
|
||||||
'selected-to': update.toV === history.selection.range.toV,\
|
|
||||||
'selected-from': update.fromV === history.selection.range.fromV,\
|
|
||||||
'hover-selected': update.toV <= history.selection.hoveredRange.toV && update.fromV >= history.selection.hoveredRange.fromV,\
|
|
||||||
'hover-selected-to': update.toV === history.selection.hoveredRange.toV,\
|
|
||||||
'hover-selected-from': update.fromV === history.selection.hoveredRange.fromV,\
|
|
||||||
}"
|
|
||||||
)
|
|
||||||
|
|
||||||
div.day(ng-if="::update.meta.first_in_day") {{ ::update.meta.end_ts | relativeDate }}
|
|
||||||
|
|
||||||
div.selectors
|
|
||||||
div.range
|
|
||||||
form
|
|
||||||
input.selector-from(
|
|
||||||
type="radio"
|
|
||||||
name="fromVersion"
|
|
||||||
ng-model="history.selection.range.fromV"
|
|
||||||
ng-value="update.fromV"
|
|
||||||
ng-mouseover="setHoverFrom(update.fromV)"
|
|
||||||
ng-mouseout="resetHover()"
|
|
||||||
ng-show="update.fromV < history.selection.range.fromV || update.toV <= history.selection.range.toV && update.fromV >= history.selection.range.fromV"
|
|
||||||
)
|
|
||||||
form
|
|
||||||
input.selector-to(
|
|
||||||
type="radio"
|
|
||||||
name="toVersion"
|
|
||||||
ng-model="history.selection.range.toV"
|
|
||||||
ng-value="update.toV"
|
|
||||||
ng-mouseover="setHoverTo(update.toV)"
|
|
||||||
ng-mouseout="resetHover()"
|
|
||||||
ng-show="update.toV > history.selection.range.toV || update.toV <= history.selection.range.toV && update.fromV >= history.selection.range.fromV"
|
|
||||||
)
|
|
||||||
|
|
||||||
div.description(ng-click="select(update.toV, update.fromV)")
|
|
||||||
history-label(
|
|
||||||
ng-repeat="label in update.labels track by label.id"
|
|
||||||
label-text="label.comment"
|
|
||||||
label-owner-name="getDisplayNameById(label.user_id)"
|
|
||||||
label-creation-date-time="label.created_at"
|
|
||||||
is-owned-by-current-user="label.user_id === user.id"
|
|
||||||
on-label-delete="deleteLabel(label)"
|
|
||||||
)
|
|
||||||
div.time {{ ::update.meta.end_ts | formatDate:'h:mm a' }}
|
|
||||||
div.action.action-edited(ng-if="::history.isV2 && update.pathnames.length > 0")
|
|
||||||
| #{translate("file_action_edited")}
|
|
||||||
div.docs(ng-repeat="pathname in ::update.pathnames")
|
|
||||||
.doc {{ ::pathname }}
|
|
||||||
div.docs(ng-repeat="project_op in ::update.project_ops")
|
|
||||||
div(ng-if="::project_op.rename")
|
|
||||||
.action #{translate("file_action_renamed")}
|
|
||||||
.doc {{ ::project_op.rename.pathname }} → {{ ::project_op.rename.newPathname }}
|
|
||||||
div(ng-if="::project_op.add")
|
|
||||||
.action #{translate("file_action_created")}
|
|
||||||
.doc {{ ::project_op.add.pathname }}
|
|
||||||
div(ng-if="::project_op.remove")
|
|
||||||
.action #{translate("file_action_deleted")}
|
|
||||||
.doc {{ ::project_op.remove.pathname }}
|
|
||||||
div.users
|
|
||||||
div.user(ng-repeat="update_user in ::update.meta.users")
|
|
||||||
.color-square(ng-if="::update_user != null", ng-style="::{'background-color': 'hsl({{ update_user.hue }}, 70%, 50%)'}")
|
|
||||||
.color-square(ng-if="::update_user == null", ng-style="::{'background-color': 'hsl(100, 70%, 50%)'}")
|
|
||||||
.name(ng-if="::update_user && update_user.id != user.id" ng-bind="getDisplayNameForUser(update_user)")
|
|
||||||
.name(ng-if="::update_user && update_user.id == user.id") You
|
|
||||||
.name(ng-if="::update_user == null") #{translate("anonymous")}
|
|
||||||
div.user(ng-if="::update.meta.users.length == 0")
|
|
||||||
.color-square(style="background-color: hsl(100, 100%, 50%)")
|
|
||||||
span #{translate("anonymous")}
|
|
||||||
|
|
||||||
.loading(ng-show="history.loading")
|
|
||||||
i.fa.fa-spin.fa-refresh
|
|
||||||
| #{translate("loading")}...
|
|
||||||
.history-entries-list-upgrade-prompt(
|
|
||||||
ng-if="history.freeHistoryLimitHit && project.owner._id === user.id"
|
|
||||||
ng-controller="FreeTrialModalController"
|
|
||||||
)
|
|
||||||
p #{translate("currently_seeing_only_24_hrs_history")}
|
|
||||||
p: strong #{translate("upgrade_to_get_feature", {feature:"full Project History"})}
|
|
||||||
ul.list-unstyled
|
|
||||||
li
|
|
||||||
i.fa.fa-check
|
|
||||||
| #{translate("unlimited_projects")}
|
|
||||||
|
|
||||||
li
|
|
||||||
i.fa.fa-check
|
|
||||||
| #{translate("collabs_per_proj", {collabcount:'Multiple'})}
|
|
||||||
|
|
||||||
li
|
|
||||||
i.fa.fa-check
|
|
||||||
| #{translate("full_doc_history")}
|
|
||||||
|
|
||||||
li
|
|
||||||
i.fa.fa-check
|
|
||||||
| #{translate("sync_to_dropbox")}
|
|
||||||
|
|
||||||
li
|
|
||||||
i.fa.fa-check
|
|
||||||
| #{translate("sync_to_github")}
|
|
||||||
|
|
||||||
li
|
|
||||||
i.fa.fa-check
|
|
||||||
|#{translate("compile_larger_projects")}
|
|
||||||
p.text-center
|
|
||||||
a.btn.btn-success(
|
|
||||||
href
|
|
||||||
ng-class="buttonClass"
|
|
||||||
ng-click="startFreeTrial('history')"
|
|
||||||
) #{translate("start_free_trial")}
|
|
||||||
p.small(ng-show="startedFreeTrial") #{translate("refresh_page_after_starting_free_trial")}
|
|
||||||
.history-entries-list-upgrade-prompt(
|
|
||||||
ng-if="history.freeHistoryLimitHit && !project.owner._id === user.id"
|
|
||||||
)
|
|
||||||
p #{translate("currently_seeing_only_24_hrs_history")}
|
|
||||||
strong #{translate("ask_proj_owner_to_upgrade_for_full_history")}
|
|
||||||
.history-labels-list-compare(
|
|
||||||
ng-if="history.showOnlyLabels && !history.error"
|
|
||||||
)
|
|
||||||
ul.list-unstyled(
|
|
||||||
ng-class="{\
|
|
||||||
'hover-state': history.hoveringOverListSelectors\
|
|
||||||
}"
|
|
||||||
)
|
|
||||||
li.change(
|
|
||||||
ng-repeat="versionWithLabel in versionsWithLabels | orderBy:'-version' track by versionWithLabel.version"
|
|
||||||
ng-class="{\
|
|
||||||
'selected': versionWithLabel.version <= history.selection.range.toV && versionWithLabel.version >= history.selection.range.fromV,\
|
|
||||||
'selected-to': versionWithLabel.version === history.selection.range.toV,\
|
|
||||||
'selected-from': versionWithLabel.version === history.selection.range.fromV,\
|
|
||||||
'hover-selected': versionWithLabel.version <= history.selection.hoveredRange.toV && versionWithLabel.version >= history.selection.hoveredRange.fromV,\
|
|
||||||
'hover-selected-to': versionWithLabel.version === history.selection.hoveredRange.toV,\
|
|
||||||
'hover-selected-from': versionWithLabel.version === history.selection.hoveredRange.fromV,\
|
|
||||||
}"
|
|
||||||
)
|
|
||||||
div.selectors
|
|
||||||
div.range
|
|
||||||
form
|
|
||||||
input.selector-from(
|
|
||||||
type="radio"
|
|
||||||
name="fromVersionForLabel"
|
|
||||||
ng-model="history.selection.range.fromV"
|
|
||||||
ng-value="versionWithLabel.version"
|
|
||||||
ng-mouseover="setHoverFrom(versionWithLabel.version)"
|
|
||||||
ng-mouseout="resetHover()"
|
|
||||||
ng-show="versionWithLabel.version < history.selection.range.fromV || versionWithLabel.version <= history.selection.range.toV && versionWithLabel.version >= history.selection.range.fromV"
|
|
||||||
)
|
|
||||||
form
|
|
||||||
input.selector-to(
|
|
||||||
type="radio"
|
|
||||||
name="toVersionForLabel"
|
|
||||||
ng-model="history.selection.range.toV"
|
|
||||||
ng-value="versionWithLabel.version"
|
|
||||||
ng-mouseover="setHoverTo(versionWithLabel.version)"
|
|
||||||
ng-mouseout="resetHover()"
|
|
||||||
ng-show="versionWithLabel.version > history.selection.range.toV || versionWithLabel.version <= history.selection.range.toV && versionWithLabel.version >= history.selection.range.fromV"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
.description(ng-click="addLabelVersionToSelection(versionWithLabel.version)")
|
|
||||||
div(
|
|
||||||
ng-repeat="label in versionWithLabel.labels track by label.id"
|
|
||||||
)
|
|
||||||
history-label(
|
|
||||||
show-tooltip="false"
|
|
||||||
label-text="label.comment"
|
|
||||||
is-owned-by-current-user="label.user_id === user.id"
|
|
||||||
is-pseudo-current-state-label="label.isPseudoCurrentStateLabel"
|
|
||||||
on-label-delete="deleteLabel(label)"
|
|
||||||
)
|
|
||||||
.history-entry-label-metadata
|
|
||||||
.history-entry-label-metadata-user(
|
|
||||||
ng-if="!label.isPseudoCurrentStateLabel"
|
|
||||||
ng-init="labelOwner = getUserById(label.user_id)"
|
|
||||||
)
|
|
||||||
| Saved by
|
|
||||||
span.name(
|
|
||||||
ng-if="::labelOwner && labelOwner._id !== user.id"
|
|
||||||
ng-style="::{'color': 'hsl({{ hueForUser(label.user_id) }}, 70%, 50%)'}"
|
|
||||||
) {{ ::getDisplayNameById(label.user_id) }}
|
|
||||||
span.name(
|
|
||||||
ng-if="labelOwner && labelOwner._id == user.id"
|
|
||||||
ng-style="::{'color': 'hsl({{ hueForUser(label.user_id) }}, 70%, 50%)'}"
|
|
||||||
) You
|
|
||||||
span.name(
|
|
||||||
ng-if="::labelOwner == null"
|
|
||||||
ng-style="::{'color': 'hsl(100, 70%, 50%)'}"
|
|
||||||
) #{translate("anonymous")}
|
|
||||||
time.history-entry-label-metadata-time {{ ::label.created_at | formatDate }}
|
|
||||||
|
|
||||||
.loading(ng-show="history.loading")
|
|
||||||
i.fa.fa-spin.fa-refresh
|
|
||||||
| #{translate("loading")}...
|
|
||||||
|
|
||||||
script(type="text/ng-template", id="historyEntriesListTpl")
|
script(type="text/ng-template", id="historyEntriesListTpl")
|
||||||
.history-entries(
|
.history-entries(
|
||||||
|
@ -250,11 +43,15 @@ script(type="text/ng-template", id="historyEntriesListTpl")
|
||||||
.infinite-scroll-inner
|
.infinite-scroll-inner
|
||||||
history-entry(
|
history-entry(
|
||||||
ng-repeat="entry in $ctrl.entries"
|
ng-repeat="entry in $ctrl.entries"
|
||||||
|
range-selection-enabled="$ctrl.rangeSelectionEnabled"
|
||||||
|
is-dragging="$ctrl.isDragging"
|
||||||
selected-history-version="$ctrl.selectedHistoryVersion"
|
selected-history-version="$ctrl.selectedHistoryVersion"
|
||||||
|
selected-history-range="$ctrl.selectedHistoryRange"
|
||||||
|
hovered-history-range="$ctrl.hoveredHistoryRange"
|
||||||
entry="entry"
|
entry="entry"
|
||||||
current-user="$ctrl.currentUser"
|
current-user="$ctrl.currentUser"
|
||||||
users="$ctrl.users"
|
users="$ctrl.users"
|
||||||
on-select="$ctrl.onEntrySelect({ selectedEntry: selectedEntry })"
|
on-select="$ctrl.handleEntrySelect(selectedEntry)"
|
||||||
on-label-delete="$ctrl.onLabelDelete({ label: label })"
|
on-label-delete="$ctrl.onLabelDelete({ label: label })"
|
||||||
)
|
)
|
||||||
.loading(ng-show="$ctrl.isLoading")
|
.loading(ng-show="$ctrl.isLoading")
|
||||||
|
@ -307,13 +104,30 @@ script(type="text/ng-template", id="historyEntryTpl")
|
||||||
.history-entry(
|
.history-entry(
|
||||||
ng-class="{\
|
ng-class="{\
|
||||||
'history-entry-first-in-day': $ctrl.entry.meta.first_in_day,\
|
'history-entry-first-in-day': $ctrl.entry.meta.first_in_day,\
|
||||||
'history-entry-selected': $ctrl.entry.toV === $ctrl.selectedHistoryVersion,\
|
'history-entry-selected': !$ctrl.isDragging && $ctrl.isEntrySelected(),\
|
||||||
|
'history-entry-selected-to': $ctrl.rangeSelectionEnabled && !$ctrl.isDragging && $ctrl.selectedHistoryRange.toV === $ctrl.entry.toV,\
|
||||||
|
'history-entry-selected-from': $ctrl.rangeSelectionEnabled && !$ctrl.isDragging && $ctrl.selectedHistoryRange.fromV === $ctrl.entry.fromV,\
|
||||||
|
'history-entry-hover-selected': $ctrl.rangeSelectionEnabled && $ctrl.isDragging && $ctrl.isEntryHoverSelected(),\
|
||||||
|
'history-entry-hover-selected-to': $ctrl.rangeSelectionEnabled && $ctrl.isDragging && $ctrl.hoveredHistoryRange.toV === $ctrl.entry.toV,\
|
||||||
|
'history-entry-hover-selected-from': $ctrl.rangeSelectionEnabled && $ctrl.isDragging && $ctrl.hoveredHistoryRange.fromV === $ctrl.entry.fromV,\
|
||||||
}"
|
}"
|
||||||
|
history-droppable-area
|
||||||
|
history-droppable-area-on-drop="$ctrl.onDrop(boundary)"
|
||||||
|
history-droppable-area-on-over="$ctrl.onOver(boundary)"
|
||||||
)
|
)
|
||||||
|
|
||||||
time.history-entry-day(ng-if="::$ctrl.entry.meta.first_in_day") {{ ::$ctrl.entry.meta.end_ts | relativeDate }}
|
time.history-entry-day(ng-if="::$ctrl.entry.meta.first_in_day") {{ ::$ctrl.entry.meta.end_ts | relativeDate }}
|
||||||
|
|
||||||
.history-entry-details(ng-click="$ctrl.onSelect({ selectedEntry: $ctrl.entry })")
|
.history-entry-details(
|
||||||
|
ng-click="$ctrl.onSelect({ selectedEntry: $ctrl.entry })"
|
||||||
|
)
|
||||||
|
.history-entry-toV-handle(
|
||||||
|
ng-show="$ctrl.rangeSelectionEnabled && $ctrl.selectedHistoryRange && ((!$ctrl.isDragging && $ctrl.selectedHistoryRange.toV === $ctrl.entry.toV) || ($ctrl.isDragging && $ctrl.hoveredHistoryRange.toV === $ctrl.entry.toV))"
|
||||||
|
history-draggable-boundary="toV"
|
||||||
|
history-draggable-boundary-on-drag-start="$ctrl.onDraggingStart()"
|
||||||
|
history-draggable-boundary-on-drag-stop="$ctrl.onDraggingStop(isValidDrop, boundary)"
|
||||||
|
)
|
||||||
|
|
||||||
history-label(
|
history-label(
|
||||||
ng-repeat="label in $ctrl.entry.labels | orderBy : '-created_at'"
|
ng-repeat="label in $ctrl.entry.labels | orderBy : '-created_at'"
|
||||||
label-text="label.comment"
|
label-text="label.comment"
|
||||||
|
@ -342,7 +156,6 @@ script(type="text/ng-template", id="historyEntryTpl")
|
||||||
ng-if="::project_op.remove"
|
ng-if="::project_op.remove"
|
||||||
) #{translate("file_action_deleted")}
|
) #{translate("file_action_deleted")}
|
||||||
span.history-entry-change-doc {{ ::$ctrl.getProjectOpDoc(project_op) }}
|
span.history-entry-change-doc {{ ::$ctrl.getProjectOpDoc(project_op) }}
|
||||||
|
|
||||||
.history-entry-metadata
|
.history-entry-metadata
|
||||||
time.history-entry-metadata-time {{ ::$ctrl.entry.meta.end_ts | formatDate:'h:mm a' }}
|
time.history-entry-metadata-time {{ ::$ctrl.entry.meta.end_ts | formatDate:'h:mm a' }}
|
||||||
span
|
span
|
||||||
|
@ -368,12 +181,38 @@ script(type="text/ng-template", id="historyEntryTpl")
|
||||||
ng-style="$ctrl.getUserCSSStyle();"
|
ng-style="$ctrl.getUserCSSStyle();"
|
||||||
) #{translate("anonymous")}
|
) #{translate("anonymous")}
|
||||||
|
|
||||||
|
.history-entry-fromV-handle(
|
||||||
|
ng-show="$ctrl.rangeSelectionEnabled && $ctrl.selectedHistoryRange && ((!$ctrl.isDragging && $ctrl.selectedHistoryRange.fromV === $ctrl.entry.fromV) || ($ctrl.isDragging && $ctrl.hoveredHistoryRange.fromV === $ctrl.entry.fromV))"
|
||||||
|
history-draggable-boundary="fromV"
|
||||||
|
history-draggable-boundary-on-drag-start="$ctrl.onDraggingStart()"
|
||||||
|
history-draggable-boundary-on-drag-stop="$ctrl.onDraggingStop(isValidDrop, boundary)"
|
||||||
|
)
|
||||||
|
|
||||||
script(type="text/ng-template", id="historyLabelsListTpl")
|
script(type="text/ng-template", id="historyLabelsListTpl")
|
||||||
.history-labels-list
|
.history-labels-list
|
||||||
.history-entry-label(
|
.history-version-with-label(
|
||||||
ng-repeat="label in $ctrl.labels track by label.id"
|
ng-repeat="versionWithLabel in $ctrl.versionsWithLabels | orderBy:'-version' track by versionWithLabel.version"
|
||||||
ng-click="$ctrl.onLabelSelect({ label: label })"
|
ng-class="{\
|
||||||
ng-class="{ 'history-entry-label-selected': label.id === $ctrl.selectedLabel.id }"
|
'history-version-with-label-selected': !$ctrl.isDragging && $ctrl.isVersionSelected(versionWithLabel.version),\
|
||||||
|
'history-version-with-label-selected-to': !$ctrl.isDragging && $ctrl.selectedHistoryRange.toV === versionWithLabel.version,\
|
||||||
|
'history-version-with-label-selected-from': !$ctrl.isDragging && $ctrl.selectedHistoryRange.fromV === versionWithLabel.version,\
|
||||||
|
'history-version-with-label-hover-selected': $ctrl.isDragging && $ctrl.isVersionHoverSelected(versionWithLabel.version),\
|
||||||
|
'history-version-with-label-hover-selected-to': $ctrl.isDragging && $ctrl.hoveredHistoryRange.toV === versionWithLabel.version,\
|
||||||
|
'history-version-with-label-hover-selected-from': $ctrl.isDragging && $ctrl.hoveredHistoryRange.fromV === versionWithLabel.version,\
|
||||||
|
}"
|
||||||
|
ng-click="$ctrl.handleVersionSelect(versionWithLabel)"
|
||||||
|
history-droppable-area
|
||||||
|
history-droppable-area-on-drop="$ctrl.onDrop(boundary, versionWithLabel)"
|
||||||
|
history-droppable-area-on-over="$ctrl.onOver(boundary, versionWithLabel)"
|
||||||
|
)
|
||||||
|
.history-entry-toV-handle(
|
||||||
|
ng-show="$ctrl.rangeSelectionEnabled && $ctrl.selectedHistoryRange && ((!$ctrl.isDragging && $ctrl.selectedHistoryRange.toV === versionWithLabel.version) || ($ctrl.isDragging && $ctrl.hoveredHistoryRange.toV === versionWithLabel.version))"
|
||||||
|
history-draggable-boundary="toV"
|
||||||
|
history-draggable-boundary-on-drag-start="$ctrl.onDraggingStart()"
|
||||||
|
history-draggable-boundary-on-drag-stop="$ctrl.onDraggingStop(isValidDrop, boundary)"
|
||||||
|
)
|
||||||
|
div(
|
||||||
|
ng-repeat="label in versionWithLabel.labels track by label.id"
|
||||||
)
|
)
|
||||||
history-label(
|
history-label(
|
||||||
show-tooltip="false"
|
show-tooltip="false"
|
||||||
|
@ -390,17 +229,24 @@ script(type="text/ng-template", id="historyLabelsListTpl")
|
||||||
| Saved by
|
| Saved by
|
||||||
span.name(
|
span.name(
|
||||||
ng-if="user && user._id !== $ctrl.currentUser.id"
|
ng-if="user && user._id !== $ctrl.currentUser.id"
|
||||||
ng-style="$ctrl.getUserCSSStyle(user, label);"
|
ng-style="$ctrl.getUserCSSStyle(user, versionWithLabel);"
|
||||||
) {{ ::$ctrl.displayName(user) }}
|
) {{ ::$ctrl.displayName(user) }}
|
||||||
span.name(
|
span.name(
|
||||||
ng-if="user && user._id == $ctrl.currentUser.id"
|
ng-if="user && user._id == $ctrl.currentUser.id"
|
||||||
ng-style="$ctrl.getUserCSSStyle(user, label);"
|
ng-style="$ctrl.getUserCSSStyle(user, versionWithLabel);"
|
||||||
) You
|
) You
|
||||||
span.name(
|
span.name(
|
||||||
ng-if="user == null"
|
ng-if="user == null"
|
||||||
ng-style="$ctrl.getUserCSSStyle(user, label);"
|
ng-style="$ctrl.getUserCSSStyle(user, versionWithLabel);"
|
||||||
) #{translate("anonymous")}
|
) #{translate("anonymous")}
|
||||||
time.history-entry-label-metadata-time {{ ::label.created_at | formatDate }}
|
time.history-entry-label-metadata-time {{ ::label.created_at | formatDate }}
|
||||||
|
.history-entry-fromV-handle(
|
||||||
|
ng-show="$ctrl.rangeSelectionEnabled && $ctrl.selectedHistoryRange && ((!$ctrl.isDragging && $ctrl.selectedHistoryRange.fromV === versionWithLabel.version) || ($ctrl.isDragging && $ctrl.hoveredHistoryRange.fromV === versionWithLabel.version))"
|
||||||
|
history-draggable-boundary="fromV"
|
||||||
|
history-draggable-boundary-on-drag-start="$ctrl.onDraggingStart()"
|
||||||
|
history-draggable-boundary-on-drag-stop="$ctrl.onDraggingStop(isValidDrop, boundary)"
|
||||||
|
)
|
||||||
|
|
||||||
.loading(ng-show="$ctrl.isLoading")
|
.loading(ng-show="$ctrl.isLoading")
|
||||||
i.fa.fa-spin.fa-refresh
|
i.fa.fa-spin.fa-refresh
|
||||||
| #{translate("loading")}...
|
| #{translate("loading")}...
|
|
@ -2,7 +2,7 @@
|
||||||
ng-if="history.isV2 && history.viewMode === HistoryViewModes.COMPARE"
|
ng-if="history.isV2 && history.viewMode === HistoryViewModes.COMPARE"
|
||||||
)
|
)
|
||||||
.diff(
|
.diff(
|
||||||
ng-if="!!history.selection.diff && !history.selection.diff.loading && !history.selection.diff.error",
|
ng-if="!!history.selection.diff && !isHistoryLoading() && !history.selection.diff.error",
|
||||||
ng-class="{ 'diff-binary': history.selection.diff.binary }"
|
ng-class="{ 'diff-binary': history.selection.diff.binary }"
|
||||||
)
|
)
|
||||||
.diff-editor-v2.hide-ace-cursor(
|
.diff-editor-v2.hide-ace-cursor(
|
||||||
|
@ -19,10 +19,10 @@
|
||||||
.alert.alert-info(ng-if="history.selection.diff.binary")
|
.alert.alert-info(ng-if="history.selection.diff.binary")
|
||||||
| We're still working on showing image and binary changes, sorry. Stay tuned!
|
| We're still working on showing image and binary changes, sorry. Stay tuned!
|
||||||
|
|
||||||
.loading-panel(ng-show="history.selection.diff.loading")
|
.loading-panel(ng-show="isHistoryLoading()")
|
||||||
i.fa.fa-spin.fa-refresh
|
i.fa.fa-spin.fa-refresh
|
||||||
| #{translate("loading")}...
|
| #{translate("loading")}...
|
||||||
.error-panel(ng-show="history.selection.diff.error")
|
.error-panel(ng-show="history.selection.diff.error && !isHistoryLoading()")
|
||||||
.alert.alert-danger #{translate("generic_something_went_wrong")}
|
.alert.alert-danger #{translate("generic_something_went_wrong")}
|
||||||
|
|
||||||
.point-in-time-panel.full-size(
|
.point-in-time-panel.full-size(
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
)
|
)
|
||||||
.alert.alert-info(ng-if="history.selection.file.binary")
|
.alert.alert-info(ng-if="history.selection.file.binary")
|
||||||
| We're still working on showing image and binary changes, sorry. Stay tuned!
|
| We're still working on showing image and binary changes, sorry. Stay tuned!
|
||||||
.loading-panel(ng-show="history.selection.file.loading")
|
.loading-panel(ng-show="isHistoryLoading()")
|
||||||
i.fa.fa-spin.fa-refresh
|
i.fa.fa-spin.fa-refresh
|
||||||
| #{translate("loading")}...
|
| #{translate("loading")}...
|
||||||
.error-panel(ng-show="history.error")
|
.error-panel(ng-show="history.error")
|
||||||
|
|
|
@ -2,28 +2,32 @@
|
||||||
ng-controller="HistoryV2ToolbarController"
|
ng-controller="HistoryV2ToolbarController"
|
||||||
ng-if="ui.view == 'history' && history.isV2"
|
ng-if="ui.view == 'history' && history.isV2"
|
||||||
)
|
)
|
||||||
span.history-toolbar-selected-version(ng-show="history.loadingFileTree || history.selection.diff.loading")
|
span.history-toolbar-selected-version(ng-show="history.loadingFileTree")
|
||||||
i.fa.fa-spin.fa-refresh
|
i.fa.fa-spin.fa-refresh
|
||||||
| #{translate("loading")}...
|
| #{translate("loading")}...
|
||||||
|
|
||||||
//- point-in-time mode info
|
//- point-in-time mode info
|
||||||
span.history-toolbar-selected-version(
|
span.history-toolbar-selected-version(
|
||||||
ng-show="!history.loadingFileTree && !history.showOnlyLabels && history.selection.update && !history.error"
|
ng-show="!history.loadingFileTree && history.viewMode === HistoryViewModes.POINT_IN_TIME && !history.showOnlyLabels && currentUpdate && !history.error"
|
||||||
) #{translate("browsing_project_as_of")}
|
) #{translate("browsing_project_as_of")}
|
||||||
time.history-toolbar-time {{ history.selection.update.meta.end_ts | formatDate:'Do MMM YYYY, h:mm a' }}
|
time.history-toolbar-time {{ currentUpdate.meta.end_ts | formatDate:'Do MMM YYYY, h:mm a' }}
|
||||||
span.history-toolbar-selected-version(
|
span.history-toolbar-selected-version(
|
||||||
ng-show="!history.loadingFileTree && history.showOnlyLabels && history.selection.label && !history.error"
|
ng-show="!history.loadingFileTree && history.viewMode === HistoryViewModes.POINT_IN_TIME && history.showOnlyLabels && currentUpdate && !history.error"
|
||||||
)
|
)
|
||||||
span(ng-if="history.selection.label.comment && !history.selection.label.isPseudoCurrentStateLabel")
|
span(ng-if="currentUpdate.labels.length > 0")
|
||||||
| #{translate("browsing_project_labelled")}
|
| #{translate("browsing_project_labelled")}
|
||||||
span.history-toolbar-selected-label "{{ history.selection.label.comment }}"
|
span.history-toolbar-selected-label(
|
||||||
span.history-toolbar-selected-label(ng-if="history.selection.label.isPseudoCurrentStateLabel")
|
ng-repeat="label in currentUpdate.labels"
|
||||||
|
)
|
||||||
|
| {{ label.comment }}
|
||||||
|
span(ng-if="!$last") ,
|
||||||
|
span.history-toolbar-selected-label(ng-if="currentUpdate.labels.length === 0 && history.labels[0].isPseudoCurrentStateLabel && currentUpdate.toV === history.labels[0].version")
|
||||||
| #{translate("browsing_project_latest_for_pseudo_label")}
|
| #{translate("browsing_project_latest_for_pseudo_label")}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//- compare mode info
|
//- compare mode info
|
||||||
span.history-toolbar-selected-version(ng-show="history.viewMode === HistoryViewModes.COMPARE && history.selection.diff && !history.selection.diff.binary && !history.selection.diff.loading && !history.selection.diff.error && !history.loadingFileTree")
|
span.history-toolbar-selected-version(ng-if="history.viewMode === HistoryViewModes.COMPARE && history.selection.diff && !history.selection.diff.binary && !history.selection.diff.loading && !history.selection.diff.error && !history.loadingFileTree")
|
||||||
| <strong>{{history.selection.diff.highlights.length}} </strong>
|
| <strong>{{history.selection.diff.highlights.length}} </strong>
|
||||||
ng-pluralize(
|
ng-pluralize(
|
||||||
count="history.selection.diff.highlights.length",
|
count="history.selection.diff.highlights.length",
|
||||||
|
@ -41,13 +45,13 @@
|
||||||
button.history-toolbar-btn(
|
button.history-toolbar-btn(
|
||||||
ng-click="showAddLabelDialog();"
|
ng-click="showAddLabelDialog();"
|
||||||
ng-if="!history.showOnlyLabels"
|
ng-if="!history.showOnlyLabels"
|
||||||
ng-disabled="history.loadingFileTree || history.selection.range.toV == null || history.selection.range.fromV == null"
|
ng-disabled="isHistoryLoading() || history.selection.range.toV == null || history.selection.range.fromV == null"
|
||||||
)
|
)
|
||||||
i.fa.fa-tag
|
i.fa.fa-tag
|
||||||
| #{translate("history_label_this_version")}
|
| #{translate("history_label_this_version")}
|
||||||
button.history-toolbar-btn(
|
button.history-toolbar-btn(
|
||||||
ng-click="toggleHistoryViewMode();"
|
ng-click="toggleHistoryViewMode();"
|
||||||
ng-disabled="history.loadingFileTree"
|
ng-disabled="isHistoryLoading()"
|
||||||
)
|
)
|
||||||
i.fa.fa-exchange
|
i.fa.fa-exchange
|
||||||
| #{translate("compare_to_another_version")}
|
| #{translate("compare_to_another_version")}
|
||||||
|
@ -68,6 +72,7 @@
|
||||||
)
|
)
|
||||||
button.history-toolbar-btn(
|
button.history-toolbar-btn(
|
||||||
ng-click="toggleHistoryViewMode();"
|
ng-click="toggleHistoryViewMode();"
|
||||||
|
ng-disabled="isHistoryLoading()"
|
||||||
)
|
)
|
||||||
i.fa
|
i.fa
|
||||||
| #{translate("view_single_version")}
|
| #{translate("view_single_version")}
|
||||||
|
|
180
services/web/public/js/libs/jquery.ui.touch-punch.js
vendored
Normal file
180
services/web/public/js/libs/jquery.ui.touch-punch.js
vendored
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
/*!
|
||||||
|
* jQuery UI Touch Punch 0.2.3
|
||||||
|
*
|
||||||
|
* Copyright 2011–2014, Dave Furfero
|
||||||
|
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||||
|
*
|
||||||
|
* Depends:
|
||||||
|
* jquery.ui.widget.js
|
||||||
|
* jquery.ui.mouse.js
|
||||||
|
*/
|
||||||
|
(function ($) {
|
||||||
|
|
||||||
|
// Detect touch support
|
||||||
|
$.support.touch = 'ontouchend' in document;
|
||||||
|
|
||||||
|
// Ignore browsers without touch support
|
||||||
|
if (!$.support.touch) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mouseProto = $.ui.mouse.prototype,
|
||||||
|
_mouseInit = mouseProto._mouseInit,
|
||||||
|
_mouseDestroy = mouseProto._mouseDestroy,
|
||||||
|
touchHandled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulate a mouse event based on a corresponding touch event
|
||||||
|
* @param {Object} event A touch event
|
||||||
|
* @param {String} simulatedType The corresponding mouse event
|
||||||
|
*/
|
||||||
|
function simulateMouseEvent (event, simulatedType) {
|
||||||
|
|
||||||
|
// Ignore multi-touch events
|
||||||
|
if (event.originalEvent.touches.length > 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
var touch = event.originalEvent.changedTouches[0],
|
||||||
|
simulatedEvent = document.createEvent('MouseEvents');
|
||||||
|
|
||||||
|
// Initialize the simulated mouse event using the touch event's coordinates
|
||||||
|
simulatedEvent.initMouseEvent(
|
||||||
|
simulatedType, // type
|
||||||
|
true, // bubbles
|
||||||
|
true, // cancelable
|
||||||
|
window, // view
|
||||||
|
1, // detail
|
||||||
|
touch.screenX, // screenX
|
||||||
|
touch.screenY, // screenY
|
||||||
|
touch.clientX, // clientX
|
||||||
|
touch.clientY, // clientY
|
||||||
|
false, // ctrlKey
|
||||||
|
false, // altKey
|
||||||
|
false, // shiftKey
|
||||||
|
false, // metaKey
|
||||||
|
0, // button
|
||||||
|
null // relatedTarget
|
||||||
|
);
|
||||||
|
|
||||||
|
// Dispatch the simulated event to the target element
|
||||||
|
event.target.dispatchEvent(simulatedEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the jQuery UI widget's touchstart events
|
||||||
|
* @param {Object} event The widget element's touchstart event
|
||||||
|
*/
|
||||||
|
mouseProto._touchStart = function (event) {
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// Ignore the event if another widget is already being handled
|
||||||
|
if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the flag to prevent other widgets from inheriting the touch event
|
||||||
|
touchHandled = true;
|
||||||
|
|
||||||
|
// Track movement to determine if interaction was a click
|
||||||
|
self._touchMoved = false;
|
||||||
|
|
||||||
|
// Simulate the mouseover event
|
||||||
|
simulateMouseEvent(event, 'mouseover');
|
||||||
|
|
||||||
|
// Simulate the mousemove event
|
||||||
|
simulateMouseEvent(event, 'mousemove');
|
||||||
|
|
||||||
|
// Simulate the mousedown event
|
||||||
|
simulateMouseEvent(event, 'mousedown');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the jQuery UI widget's touchmove events
|
||||||
|
* @param {Object} event The document's touchmove event
|
||||||
|
*/
|
||||||
|
mouseProto._touchMove = function (event) {
|
||||||
|
|
||||||
|
// Ignore event if not handled
|
||||||
|
if (!touchHandled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interaction was not a click
|
||||||
|
this._touchMoved = true;
|
||||||
|
|
||||||
|
// Simulate the mousemove event
|
||||||
|
simulateMouseEvent(event, 'mousemove');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the jQuery UI widget's touchend events
|
||||||
|
* @param {Object} event The document's touchend event
|
||||||
|
*/
|
||||||
|
mouseProto._touchEnd = function (event) {
|
||||||
|
|
||||||
|
// Ignore event if not handled
|
||||||
|
if (!touchHandled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate the mouseup event
|
||||||
|
simulateMouseEvent(event, 'mouseup');
|
||||||
|
|
||||||
|
// Simulate the mouseout event
|
||||||
|
simulateMouseEvent(event, 'mouseout');
|
||||||
|
|
||||||
|
// If the touch interaction did not move, it should trigger a click
|
||||||
|
if (!this._touchMoved) {
|
||||||
|
|
||||||
|
// Simulate the click event
|
||||||
|
simulateMouseEvent(event, 'click');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unset the flag to allow other widgets to inherit the touch event
|
||||||
|
touchHandled = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A duck punch of the $.ui.mouse _mouseInit method to support touch events.
|
||||||
|
* This method extends the widget with bound touch event handlers that
|
||||||
|
* translate touch events to mouse events and pass them to the widget's
|
||||||
|
* original mouse event handling methods.
|
||||||
|
*/
|
||||||
|
mouseProto._mouseInit = function () {
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// Delegate the touch handlers to the widget's element
|
||||||
|
self.element.bind({
|
||||||
|
touchstart: $.proxy(self, '_touchStart'),
|
||||||
|
touchmove: $.proxy(self, '_touchMove'),
|
||||||
|
touchend: $.proxy(self, '_touchEnd')
|
||||||
|
});
|
||||||
|
|
||||||
|
// Call the original $.ui.mouse init method
|
||||||
|
_mouseInit.call(self);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the touch event handlers
|
||||||
|
*/
|
||||||
|
mouseProto._mouseDestroy = function () {
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// Delegate the touch handlers to the widget's element
|
||||||
|
self.element.unbind({
|
||||||
|
touchstart: $.proxy(self, '_touchStart'),
|
||||||
|
touchmove: $.proxy(self, '_touchMove'),
|
||||||
|
touchend: $.proxy(self, '_touchEnd')
|
||||||
|
});
|
||||||
|
|
||||||
|
// Call the original $.ui.mouse destroy method
|
||||||
|
_mouseDestroy.call(self);
|
||||||
|
};
|
||||||
|
|
||||||
|
})(jQuery);
|
|
@ -13,7 +13,7 @@
|
||||||
* DS207: Consider shorter variations of null checks
|
* DS207: Consider shorter variations of null checks
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||||
*/
|
*/
|
||||||
define(['base', 'libs/jquery-layout'], App =>
|
define(['base', 'libs/jquery-layout', 'libs/jquery.ui.touch-punch'], App =>
|
||||||
App.directive('layout', [
|
App.directive('layout', [
|
||||||
'$parse',
|
'$parse',
|
||||||
'$compile',
|
'$compile',
|
||||||
|
|
|
@ -19,7 +19,6 @@ define([
|
||||||
'moment',
|
'moment',
|
||||||
'ide/colors/ColorManager',
|
'ide/colors/ColorManager',
|
||||||
'ide/history/util/displayNameForUser',
|
'ide/history/util/displayNameForUser',
|
||||||
'ide/history/controllers/HistoryCompareController',
|
|
||||||
'ide/history/controllers/HistoryListController',
|
'ide/history/controllers/HistoryListController',
|
||||||
'ide/history/controllers/HistoryDiffController',
|
'ide/history/controllers/HistoryDiffController',
|
||||||
'ide/history/directives/infiniteScroll'
|
'ide/history/directives/infiniteScroll'
|
||||||
|
|
|
@ -28,6 +28,8 @@ define([
|
||||||
'ide/history/controllers/HistoryV2AddLabelModalController',
|
'ide/history/controllers/HistoryV2AddLabelModalController',
|
||||||
'ide/history/controllers/HistoryV2DeleteLabelModalController',
|
'ide/history/controllers/HistoryV2DeleteLabelModalController',
|
||||||
'ide/history/directives/infiniteScroll',
|
'ide/history/directives/infiniteScroll',
|
||||||
|
'ide/history/directives/historyDraggableBoundary',
|
||||||
|
'ide/history/directives/historyDroppableArea',
|
||||||
'ide/history/components/historyEntriesList',
|
'ide/history/components/historyEntriesList',
|
||||||
'ide/history/components/historyEntry',
|
'ide/history/components/historyEntry',
|
||||||
'ide/history/components/historyLabelsList',
|
'ide/history/components/historyLabelsList',
|
||||||
|
@ -57,6 +59,7 @@ define([
|
||||||
$scope.project_id
|
$scope.project_id
|
||||||
}`
|
}`
|
||||||
this._previouslySelectedPathname = null
|
this._previouslySelectedPathname = null
|
||||||
|
this._loadFileTreeRequestCanceller = null
|
||||||
this.hardReset()
|
this.hardReset()
|
||||||
|
|
||||||
this.$scope.toggleHistory = () => {
|
this.$scope.toggleHistory = () => {
|
||||||
|
@ -71,24 +74,19 @@ define([
|
||||||
}, 0)
|
}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$scope.$watchGroup(
|
this.$scope.isHistoryLoading = () => {
|
||||||
['history.selection.range.toV', 'history.selection.range.fromV'],
|
let selection = this.$scope.history.selection
|
||||||
(newRange, prevRange) => {
|
return (
|
||||||
if (this.$scope.history.viewMode === HistoryViewModes.COMPARE) {
|
this.$scope.history.loadingFileTree ||
|
||||||
let [newTo, newFrom] = newRange
|
(this.$scope.history.viewMode === HistoryViewModes.POINT_IN_TIME &&
|
||||||
let [prevTo, prevFrom] = prevRange
|
selection.file &&
|
||||||
if (
|
selection.file.loading) ||
|
||||||
newTo != null &&
|
(this.$scope.history.viewMode === HistoryViewModes.COMPARE &&
|
||||||
newFrom != null &&
|
selection.diff &&
|
||||||
newTo !== prevTo &&
|
selection.diff.loading)
|
||||||
newFrom !== prevFrom
|
|
||||||
) {
|
|
||||||
this.loadFileTreeDiff(newTo, newFrom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
show() {
|
show() {
|
||||||
this.$scope.ui.view = 'history'
|
this.$scope.ui.view = 'history'
|
||||||
|
@ -151,8 +149,6 @@ define([
|
||||||
},
|
},
|
||||||
diff: null,
|
diff: null,
|
||||||
files: [],
|
files: [],
|
||||||
update: null,
|
|
||||||
label: null,
|
|
||||||
file: null
|
file: null
|
||||||
},
|
},
|
||||||
error: null,
|
error: null,
|
||||||
|
@ -186,8 +182,6 @@ define([
|
||||||
},
|
},
|
||||||
diff: null, // When history.viewMode == HistoryViewModes.COMPARE
|
diff: null, // When history.viewMode == HistoryViewModes.COMPARE
|
||||||
files: [], // When history.viewMode == HistoryViewModes.COMPARE
|
files: [], // When history.viewMode == HistoryViewModes.COMPARE
|
||||||
update: null, // When history.viewMode == HistoryViewModes.POINT_IN_TIME
|
|
||||||
label: null, // When history.viewMode == HistoryViewModes.POINT_IN_TIME
|
|
||||||
file: null
|
file: null
|
||||||
}
|
}
|
||||||
this.$scope.history.error = null
|
this.$scope.history.error = null
|
||||||
|
@ -221,9 +215,9 @@ define([
|
||||||
} else {
|
} else {
|
||||||
// Point-in-time mode
|
// Point-in-time mode
|
||||||
if (this.$scope.history.showOnlyLabels) {
|
if (this.$scope.history.showOnlyLabels) {
|
||||||
this.selectLabelFromUpdatesSelection()
|
this.autoSelectLabelForPointInTime()
|
||||||
} else {
|
} else {
|
||||||
this.autoSelectLastVersionForPointInTime()
|
this.autoSelectVersionForPointInTime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,14 +282,23 @@ define([
|
||||||
let selection = this.$scope.history.selection
|
let selection = this.$scope.history.selection
|
||||||
const query = [`from=${fromV}`, `to=${toV}`]
|
const query = [`from=${fromV}`, `to=${toV}`]
|
||||||
url += `?${query.join('&')}`
|
url += `?${query.join('&')}`
|
||||||
this.$scope.history.loadingFileTree = true
|
|
||||||
|
this.$scope.$applyAsync(
|
||||||
|
() => (this.$scope.history.loadingFileTree = true)
|
||||||
|
)
|
||||||
|
|
||||||
selection.file = null
|
selection.file = null
|
||||||
selection.pathname = null
|
selection.pathname = null
|
||||||
if (selection.diff) {
|
|
||||||
selection.diff.loading = true
|
// If `this._loadFileTreeRequestCanceller` is not null, then we have a request inflight
|
||||||
|
if (this._loadFileTreeRequestCanceller != null) {
|
||||||
|
// Resolving it will cancel the inflight request (or, rather, ignore its result)
|
||||||
|
this._loadFileTreeRequestCanceller.resolve()
|
||||||
}
|
}
|
||||||
|
this._loadFileTreeRequestCanceller = this.ide.$q.defer()
|
||||||
|
|
||||||
return this.ide.$http
|
return this.ide.$http
|
||||||
.get(url)
|
.get(url, { timeout: this._loadFileTreeRequestCanceller.promise })
|
||||||
.then(response => {
|
.then(response => {
|
||||||
this.$scope.history.selection.files = response.data.diff
|
this.$scope.history.selection.files = response.data.diff
|
||||||
for (let file of this.$scope.history.selection.files) {
|
for (let file of this.$scope.history.selection.files) {
|
||||||
|
@ -305,15 +308,15 @@ define([
|
||||||
delete file.newPathname
|
delete file.newPathname
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this._loadFileTreeRequestCanceller = null
|
||||||
|
this.$scope.history.loadingFileTree = false
|
||||||
this.autoSelectFile()
|
this.autoSelectFile()
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error(err)
|
if (err.status !== -1) {
|
||||||
})
|
this._loadFileTreeRequestCanceller = null
|
||||||
.finally(() => {
|
} else {
|
||||||
this.$scope.history.loadingFileTree = false
|
this.$scope.history.loadingFileTree = false
|
||||||
if (selection.diff) {
|
|
||||||
selection.diff.loading = true
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -380,7 +383,8 @@ define([
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$scope.history.selection.range.toV = this.$scope.history.updates[0].toV
|
let toV = this.$scope.history.updates[0].toV
|
||||||
|
let fromV = null
|
||||||
|
|
||||||
let indexOfLastUpdateNotByMe = 0
|
let indexOfLastUpdateNotByMe = 0
|
||||||
for (let i = 0; i < this.$scope.history.updates.length; i++) {
|
for (let i = 0; i < this.$scope.history.updates.length; i++) {
|
||||||
|
@ -394,19 +398,24 @@ define([
|
||||||
indexOfLastUpdateNotByMe = i
|
indexOfLastUpdateNotByMe = i
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$scope.history.selection.range.fromV = this.$scope.history.updates[
|
fromV = this.$scope.history.updates[indexOfLastUpdateNotByMe].fromV
|
||||||
indexOfLastUpdateNotByMe
|
this.selectVersionsForCompare(toV, fromV)
|
||||||
].fromV
|
|
||||||
}
|
}
|
||||||
|
|
||||||
autoSelectLastVersionForPointInTime() {
|
autoSelectVersionForPointInTime() {
|
||||||
this.$scope.history.selection.label = null
|
|
||||||
if (this.$scope.history.updates.length === 0) {
|
if (this.$scope.history.updates.length === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return this.selectVersionForPointInTime(
|
let versionToSelect = this.$scope.history.updates[0].toV
|
||||||
this.$scope.history.updates[0].toV
|
let range = this.$scope.history.selection.range
|
||||||
)
|
if (
|
||||||
|
range.toV != null &&
|
||||||
|
range.fromV != null &&
|
||||||
|
range.toV === range.fromV
|
||||||
|
) {
|
||||||
|
versionToSelect = range.toV
|
||||||
|
}
|
||||||
|
this.selectVersionForPointInTime(versionToSelect)
|
||||||
}
|
}
|
||||||
|
|
||||||
autoSelectLastLabel() {
|
autoSelectLastLabel() {
|
||||||
|
@ -429,14 +438,27 @@ define([
|
||||||
|
|
||||||
selectVersionForPointInTime(version) {
|
selectVersionForPointInTime(version) {
|
||||||
let selection = this.$scope.history.selection
|
let selection = this.$scope.history.selection
|
||||||
|
if (
|
||||||
|
selection.range.toV !== version &&
|
||||||
|
selection.range.fromV !== version
|
||||||
|
) {
|
||||||
selection.range.toV = version
|
selection.range.toV = version
|
||||||
selection.range.fromV = version
|
selection.range.fromV = version
|
||||||
selection.update = this._getUpdateForVersion(version)
|
|
||||||
this.loadFileTreeForVersion(version)
|
this.loadFileTreeForVersion(version)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
selectLabelFromUpdatesSelection() {
|
selectVersionsForCompare(toV, fromV) {
|
||||||
const selectedUpdate = this._getUpdateForVersion(
|
let range = this.$scope.history.selection.range
|
||||||
|
if (range.toV !== toV || range.fromV !== fromV) {
|
||||||
|
range.toV = toV
|
||||||
|
range.fromV = fromV
|
||||||
|
this.loadFileTreeDiff(toV, fromV)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
autoSelectLabelForPointInTime() {
|
||||||
|
const selectedUpdate = this.getUpdateForVersion(
|
||||||
this.$scope.history.selection.range.toV
|
this.$scope.history.selection.range.toV
|
||||||
)
|
)
|
||||||
let nSelectedLabels = 0
|
let nSelectedLabels = 0
|
||||||
|
@ -450,9 +472,7 @@ define([
|
||||||
this.autoSelectLastLabel()
|
this.autoSelectLastLabel()
|
||||||
// If the update has one label, select it
|
// If the update has one label, select it
|
||||||
} else if (nSelectedLabels === 1) {
|
} else if (nSelectedLabels === 1) {
|
||||||
this.selectLabelForPointInTime(
|
this.selectLabelForPointInTime(selectedUpdate.labels[0])
|
||||||
this.$scope.history.selection.update.labels[0]
|
|
||||||
)
|
|
||||||
// If there are multiple labels for the update, select the latest
|
// If there are multiple labels for the update, select the latest
|
||||||
} else if (nSelectedLabels > 1) {
|
} else if (nSelectedLabels > 1) {
|
||||||
const sortedLabels = this.ide.$filter('orderBy')(
|
const sortedLabels = this.ide.$filter('orderBy')(
|
||||||
|
@ -479,19 +499,17 @@ define([
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$scope.history.selection.label = labelToSelect
|
|
||||||
if (updateToSelect != null) {
|
if (updateToSelect != null) {
|
||||||
this.selectVersionForPointInTime(updateToSelect.toV)
|
this.selectVersionForPointInTime(updateToSelect.toV)
|
||||||
} else {
|
} else {
|
||||||
let selection = this.$scope.history.selection
|
let selection = this.$scope.history.selection
|
||||||
selection.range.toV = labelToSelect.version
|
selection.range.toV = labelToSelect.version
|
||||||
selection.range.fromV = labelToSelect.version
|
selection.range.fromV = labelToSelect.version
|
||||||
selection.update = null
|
|
||||||
this.loadFileTreeForVersion(labelToSelect.version)
|
this.loadFileTreeForVersion(labelToSelect.version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_getUpdateForVersion(version) {
|
getUpdateForVersion(version) {
|
||||||
for (let update of this.$scope.history.updates) {
|
for (let update of this.$scope.history.updates) {
|
||||||
if (update.toV === version) {
|
if (update.toV === version) {
|
||||||
return update
|
return update
|
||||||
|
@ -501,17 +519,16 @@ define([
|
||||||
|
|
||||||
autoSelectLabelsForComparison() {
|
autoSelectLabelsForComparison() {
|
||||||
let labels = this.$scope.history.labels
|
let labels = this.$scope.history.labels
|
||||||
let selection = this.$scope.history.selection
|
|
||||||
let nLabels = 0
|
let nLabels = 0
|
||||||
if (Array.isArray(labels)) {
|
if (Array.isArray(labels)) {
|
||||||
nLabels = labels.length
|
nLabels = labels.length
|
||||||
}
|
}
|
||||||
if (nLabels === 1) {
|
if (nLabels === 0) {
|
||||||
selection.range.toV = labels[0].version
|
// TODO better handling
|
||||||
selection.range.fromV = labels[0].version
|
} else if (nLabels === 1) {
|
||||||
|
this.selectVersionsForCompare(labels[0].version, labels[0].version)
|
||||||
} else if (nLabels > 1) {
|
} else if (nLabels > 1) {
|
||||||
selection.range.toV = labels[0].version
|
this.selectVersionsForCompare(labels[0].version, labels[1].version)
|
||||||
selection.range.fromV = labels[1].version
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,26 +590,27 @@ define([
|
||||||
|
|
||||||
_loadLabels(labels, lastUpdateToV) {
|
_loadLabels(labels, lastUpdateToV) {
|
||||||
let sortedLabels = this._sortLabelsByVersionAndDate(labels)
|
let sortedLabels = this._sortLabelsByVersionAndDate(labels)
|
||||||
|
let nLabels = sortedLabels.length
|
||||||
let hasPseudoCurrentStateLabel = false
|
let hasPseudoCurrentStateLabel = false
|
||||||
let needsPseudoCurrentStateLabel = false
|
let needsPseudoCurrentStateLabel = false
|
||||||
if (sortedLabels.length > 0 && lastUpdateToV) {
|
if (lastUpdateToV) {
|
||||||
hasPseudoCurrentStateLabel = sortedLabels[0].isPseudoCurrentStateLabel
|
hasPseudoCurrentStateLabel =
|
||||||
|
nLabels > 0 ? sortedLabels[0].isPseudoCurrentStateLabel : false
|
||||||
if (hasPseudoCurrentStateLabel) {
|
if (hasPseudoCurrentStateLabel) {
|
||||||
needsPseudoCurrentStateLabel =
|
needsPseudoCurrentStateLabel =
|
||||||
sortedLabels.length > 1
|
nLabels > 1 ? sortedLabels[1].version !== lastUpdateToV : false
|
||||||
? sortedLabels[1].version !== lastUpdateToV
|
|
||||||
: false
|
|
||||||
} else {
|
} else {
|
||||||
needsPseudoCurrentStateLabel =
|
needsPseudoCurrentStateLabel =
|
||||||
sortedLabels[0].version !== lastUpdateToV
|
nLabels > 0 ? sortedLabels[0].version !== lastUpdateToV : true
|
||||||
}
|
}
|
||||||
if (needsPseudoCurrentStateLabel && !hasPseudoCurrentStateLabel) {
|
if (needsPseudoCurrentStateLabel && !hasPseudoCurrentStateLabel) {
|
||||||
sortedLabels.unshift({
|
let pseudoCurrentStateLabel = {
|
||||||
id: '1',
|
id: '1',
|
||||||
isPseudoCurrentStateLabel: true,
|
isPseudoCurrentStateLabel: true,
|
||||||
version: lastUpdateToV,
|
version: lastUpdateToV,
|
||||||
created_at: new Date().toISOString()
|
created_at: new Date().toISOString()
|
||||||
})
|
}
|
||||||
|
sortedLabels.unshift(pseudoCurrentStateLabel)
|
||||||
} else if (
|
} else if (
|
||||||
!needsPseudoCurrentStateLabel &&
|
!needsPseudoCurrentStateLabel &&
|
||||||
hasPseudoCurrentStateLabel
|
hasPseudoCurrentStateLabel
|
||||||
|
@ -638,8 +656,6 @@ define([
|
||||||
|
|
||||||
reloadDiff() {
|
reloadDiff() {
|
||||||
let { diff } = this.$scope.history.selection
|
let { diff } = this.$scope.history.selection
|
||||||
// const { updates } = this.$scope.history.selection
|
|
||||||
// const { fromV, toV, pathname } = this._calculateDiffDataFromSelection()
|
|
||||||
const { range, pathname } = this.$scope.history.selection
|
const { range, pathname } = this.$scope.history.selection
|
||||||
const { fromV, toV } = range
|
const { fromV, toV } = range
|
||||||
|
|
||||||
|
@ -654,7 +670,7 @@ define([
|
||||||
diff.fromV === fromV &&
|
diff.fromV === fromV &&
|
||||||
diff.toV === toV
|
diff.toV === toV
|
||||||
) {
|
) {
|
||||||
return this.ide.$q.when(true)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$scope.history.selection.diff = diff = {
|
this.$scope.history.selection.diff = diff = {
|
||||||
|
@ -732,8 +748,11 @@ define([
|
||||||
}
|
}
|
||||||
|
|
||||||
_isLabelSelected(label) {
|
_isLabelSelected(label) {
|
||||||
if (this.$scope.history.selection.label) {
|
if (label) {
|
||||||
return label.id === this.$scope.history.selection.label.id
|
return (
|
||||||
|
label.version <= this.$scope.history.selection.range.toV &&
|
||||||
|
label.version >= this.$scope.history.selection.range.fromV
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,15 +11,18 @@
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||||
*/
|
*/
|
||||||
define(['base'], function(App) {
|
define(['base'], function(App) {
|
||||||
const historyEntriesListController = function($scope, $element, $attrs) {
|
const historyEntriesListController = function($scope, $element, $attrs, _) {
|
||||||
const ctrl = this
|
const ctrl = this
|
||||||
ctrl.$entryListViewportEl = null
|
ctrl.$entryListViewportEl = null
|
||||||
|
ctrl.isDragging = false
|
||||||
|
|
||||||
const _isEntryElVisible = function($entryEl) {
|
const _isEntryElVisible = function($entryEl) {
|
||||||
const entryElTop = $entryEl.offset().top
|
const entryElTop = $entryEl.offset().top
|
||||||
const entryElBottom = entryElTop + $entryEl.outerHeight()
|
const entryElBottom = entryElTop + $entryEl.outerHeight()
|
||||||
const entryListViewportElTop = ctrl.$entryListViewportEl.offset().top
|
const entryListViewportElTop = ctrl.$entryListViewportEl.offset().top
|
||||||
const entryListViewportElBottom =
|
const entryListViewportElBottom =
|
||||||
entryListViewportElTop + ctrl.$entryListViewportEl.height()
|
entryListViewportElTop + ctrl.$entryListViewportEl.height()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
entryElTop >= entryListViewportElTop &&
|
entryElTop >= entryListViewportElTop &&
|
||||||
entryElBottom <= entryListViewportElBottom
|
entryElBottom <= entryListViewportElBottom
|
||||||
|
@ -31,18 +34,86 @@ define(['base'], function(App) {
|
||||||
}
|
}
|
||||||
ctrl.onEntryLinked = function(entry, $entryEl) {
|
ctrl.onEntryLinked = function(entry, $entryEl) {
|
||||||
if (
|
if (
|
||||||
entry.toV === ctrl.selectedHistoryVersion &&
|
!ctrl.rangeSelectionEnabled &&
|
||||||
!_isEntryElVisible($entryEl)
|
entry.toV === ctrl.selectedHistoryVersion
|
||||||
) {
|
) {
|
||||||
return $scope.$applyAsync(() =>
|
$scope.$applyAsync(() => {
|
||||||
|
if (!_isEntryElVisible($entryEl)) {
|
||||||
ctrl.$entryListViewportEl.scrollTop(
|
ctrl.$entryListViewportEl.scrollTop(
|
||||||
_getScrollTopPosForEntry($entryEl)
|
_getScrollTopPosForEntry($entryEl)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctrl.$onInit = () =>
|
ctrl.handleEntrySelect = entry => {
|
||||||
(ctrl.$entryListViewportEl = $element.find('> .history-entries'))
|
if (ctrl.rangeSelectionEnabled) {
|
||||||
|
ctrl.onRangeSelect({
|
||||||
|
selectedToV: entry.toV,
|
||||||
|
selectedFromV: entry.fromV
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ctrl.onVersionSelect({ version: entry.toV })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.setRangeToV = toV => {
|
||||||
|
if (toV > ctrl.selectedHistoryRange.fromV) {
|
||||||
|
ctrl.onRangeSelect({
|
||||||
|
selectedToV: toV,
|
||||||
|
selectedFromV: ctrl.selectedHistoryRange.fromV
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.setRangeFromV = fromV => {
|
||||||
|
if (fromV < ctrl.selectedHistoryRange.toV) {
|
||||||
|
ctrl.onRangeSelect({
|
||||||
|
selectedToV: ctrl.selectedHistoryRange.toV,
|
||||||
|
selectedFromV: fromV
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.initHoveredRange = () => {
|
||||||
|
ctrl.hoveredHistoryRange = {
|
||||||
|
toV: ctrl.selectedHistoryRange.toV,
|
||||||
|
fromV: ctrl.selectedHistoryRange.fromV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.resetHoveredRange = () => {
|
||||||
|
ctrl.hoveredHistoryRange = { toV: null, fromV: null }
|
||||||
|
}
|
||||||
|
ctrl.setHoveredRangeToV = toV => {
|
||||||
|
if (toV > ctrl.hoveredHistoryRange.fromV) {
|
||||||
|
$scope.$applyAsync(() => (ctrl.hoveredHistoryRange.toV = toV))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.setHoveredRangeFromV = fromV => {
|
||||||
|
if (fromV < ctrl.hoveredHistoryRange.toV) {
|
||||||
|
$scope.$applyAsync(() => (ctrl.hoveredHistoryRange.fromV = fromV))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.onDraggingStart = () => {
|
||||||
|
$scope.$applyAsync(() => {
|
||||||
|
ctrl.isDragging = true
|
||||||
|
ctrl.initHoveredRange()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ctrl.onDraggingStop = (isValidDrop, boundary) => {
|
||||||
|
$scope.$applyAsync(() => {
|
||||||
|
ctrl.isDragging = false
|
||||||
|
if (!isValidDrop) {
|
||||||
|
if (boundary === 'toV') {
|
||||||
|
ctrl.setRangeToV(ctrl.hoveredHistoryRange.toV)
|
||||||
|
} else if (boundary === 'fromV') {
|
||||||
|
ctrl.setRangeFromV(ctrl.hoveredHistoryRange.fromV)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.resetHoveredRange()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ctrl.$onInit = () => {
|
||||||
|
ctrl.$entryListViewportEl = $element.find('> .history-entries')
|
||||||
|
ctrl.resetHoveredRange()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return App.component('historyEntriesList', {
|
return App.component('historyEntriesList', {
|
||||||
|
@ -56,8 +127,11 @@ define(['base'], function(App) {
|
||||||
currentUser: '<',
|
currentUser: '<',
|
||||||
freeHistoryLimitHit: '<',
|
freeHistoryLimitHit: '<',
|
||||||
currentUserIsOwner: '<',
|
currentUserIsOwner: '<',
|
||||||
selectedHistoryVersion: '<',
|
rangeSelectionEnabled: '<',
|
||||||
onEntrySelect: '&',
|
selectedHistoryVersion: '<?',
|
||||||
|
selectedHistoryRange: '<?',
|
||||||
|
onVersionSelect: '&',
|
||||||
|
onRangeSelect: '&',
|
||||||
onLabelDelete: '&'
|
onLabelDelete: '&'
|
||||||
},
|
},
|
||||||
controller: historyEntriesListController,
|
controller: historyEntriesListController,
|
||||||
|
|
|
@ -43,17 +43,67 @@ define([
|
||||||
(user != null ? user._id : undefined) ||
|
(user != null ? user._id : undefined) ||
|
||||||
(user != null ? user.id : undefined)
|
(user != null ? user.id : undefined)
|
||||||
const hue = ColorManager.getHueForUserId(curUserId) || 100
|
const hue = ColorManager.getHueForUserId(curUserId) || 100
|
||||||
if (ctrl.entry.toV === ctrl.selectedHistoryVersion) {
|
if (ctrl.isEntrySelected() || ctrl.isEntryHoverSelected()) {
|
||||||
return { color: '#FFF' }
|
return { color: '#FFF' }
|
||||||
} else {
|
} else {
|
||||||
return { color: `hsl(${hue}, 70%, 50%)` }
|
return { color: `hsl(${hue}, 70%, 50%)` }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctrl.$onInit = () =>
|
ctrl.isEntrySelected = function() {
|
||||||
ctrl.historyEntriesList.onEntryLinked(
|
if (ctrl.rangeSelectionEnabled) {
|
||||||
ctrl.entry,
|
return (
|
||||||
$element.find('> .history-entry')
|
ctrl.entry.toV <= ctrl.selectedHistoryRange.toV &&
|
||||||
|
ctrl.entry.fromV >= ctrl.selectedHistoryRange.fromV
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
return ctrl.entry.toV === ctrl.selectedHistoryVersion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl.isEntryHoverSelected = function() {
|
||||||
|
return (
|
||||||
|
ctrl.rangeSelectionEnabled &&
|
||||||
|
ctrl.entry.toV <= ctrl.hoveredHistoryRange.toV &&
|
||||||
|
ctrl.entry.fromV >= ctrl.hoveredHistoryRange.fromV
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl.onDraggingStart = () => {
|
||||||
|
ctrl.historyEntriesList.onDraggingStart()
|
||||||
|
}
|
||||||
|
ctrl.onDraggingStop = (isValidDrop, boundary) =>
|
||||||
|
ctrl.historyEntriesList.onDraggingStop(isValidDrop, boundary)
|
||||||
|
|
||||||
|
ctrl.onDrop = boundary => {
|
||||||
|
if (boundary === 'toV') {
|
||||||
|
$scope.$applyAsync(() =>
|
||||||
|
ctrl.historyEntriesList.setRangeToV(ctrl.entry.toV)
|
||||||
|
)
|
||||||
|
} else if (boundary === 'fromV') {
|
||||||
|
$scope.$applyAsync(() =>
|
||||||
|
ctrl.historyEntriesList.setRangeFromV(ctrl.entry.fromV)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.onOver = boundary => {
|
||||||
|
if (boundary === 'toV') {
|
||||||
|
$scope.$applyAsync(() =>
|
||||||
|
ctrl.historyEntriesList.setHoveredRangeToV(ctrl.entry.toV)
|
||||||
|
)
|
||||||
|
} else if (boundary === 'fromV') {
|
||||||
|
$scope.$applyAsync(() =>
|
||||||
|
ctrl.historyEntriesList.setHoveredRangeFromV(ctrl.entry.fromV)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl.$onInit = () => {
|
||||||
|
ctrl.$entryEl = $element.find('> .history-entry')
|
||||||
|
ctrl.$entryDetailsEl = $element.find('.history-entry-details')
|
||||||
|
ctrl.$toVHandleEl = $element.find('.history-entry-toV-handle')
|
||||||
|
ctrl.$fromVHandleEl = $element.find('.history-entry-fromV-handle')
|
||||||
|
ctrl.historyEntriesList.onEntryLinked(ctrl.entry, ctrl.$entryEl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return App.component('historyEntry', {
|
return App.component('historyEntry', {
|
||||||
|
@ -61,7 +111,11 @@ define([
|
||||||
entry: '<',
|
entry: '<',
|
||||||
currentUser: '<',
|
currentUser: '<',
|
||||||
users: '<',
|
users: '<',
|
||||||
selectedHistoryVersion: '<',
|
rangeSelectionEnabled: '<',
|
||||||
|
isDragging: '<',
|
||||||
|
selectedHistoryVersion: '<?',
|
||||||
|
selectedHistoryRange: '<?',
|
||||||
|
hoveredHistoryRange: '<?',
|
||||||
onSelect: '&',
|
onSelect: '&',
|
||||||
onLabelDelete: '&'
|
onLabelDelete: '&'
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,8 +15,125 @@ define([
|
||||||
'ide/colors/ColorManager',
|
'ide/colors/ColorManager',
|
||||||
'ide/history/util/displayNameForUser'
|
'ide/history/util/displayNameForUser'
|
||||||
], function(App, ColorManager, displayNameForUser) {
|
], function(App, ColorManager, displayNameForUser) {
|
||||||
const historyLabelsListController = function($scope, $element, $attrs) {
|
const historyLabelsListController = function($scope, $element, $attrs, _) {
|
||||||
const ctrl = this
|
const ctrl = this
|
||||||
|
ctrl.isDragging = false
|
||||||
|
ctrl.versionsWithLabels = []
|
||||||
|
$scope.$watchCollection('$ctrl.labels', function(labels) {
|
||||||
|
if (labels != null && labels.length > 0) {
|
||||||
|
const groupedLabelsHash = _.groupBy(labels, 'version')
|
||||||
|
ctrl.versionsWithLabels = _.map(
|
||||||
|
groupedLabelsHash,
|
||||||
|
(labels, version) => {
|
||||||
|
return {
|
||||||
|
version: parseInt(version, 10),
|
||||||
|
labels
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
ctrl.initHoveredRange = () => {
|
||||||
|
ctrl.hoveredHistoryRange = {
|
||||||
|
toV: ctrl.selectedHistoryRange.toV,
|
||||||
|
fromV: ctrl.selectedHistoryRange.fromV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.resetHoveredRange = () => {
|
||||||
|
ctrl.hoveredHistoryRange = { toV: null, fromV: null }
|
||||||
|
}
|
||||||
|
ctrl.setHoveredRangeToV = toV => {
|
||||||
|
if (toV >= ctrl.hoveredHistoryRange.fromV) {
|
||||||
|
ctrl.hoveredHistoryRange.toV = toV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.setHoveredRangeFromV = fromV => {
|
||||||
|
if (fromV <= ctrl.hoveredHistoryRange.toV) {
|
||||||
|
ctrl.hoveredHistoryRange.fromV = fromV
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl.isVersionSelected = function(version) {
|
||||||
|
if (ctrl.rangeSelectionEnabled) {
|
||||||
|
return (
|
||||||
|
version <= ctrl.selectedHistoryRange.toV &&
|
||||||
|
version >= ctrl.selectedHistoryRange.fromV
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return version === ctrl.selectedHistoryVersion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.isVersionHoverSelected = function(version) {
|
||||||
|
return (
|
||||||
|
ctrl.rangeSelectionEnabled &&
|
||||||
|
version <= ctrl.hoveredHistoryRange.toV &&
|
||||||
|
version >= ctrl.hoveredHistoryRange.fromV
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ctrl.onDraggingStart = () => {
|
||||||
|
$scope.$applyAsync(() => {
|
||||||
|
ctrl.isDragging = true
|
||||||
|
ctrl.initHoveredRange()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ctrl.onDraggingStop = (isValidDrop, boundary) => {
|
||||||
|
$scope.$applyAsync(() => {
|
||||||
|
if (!isValidDrop) {
|
||||||
|
if (boundary === 'toV') {
|
||||||
|
ctrl.setRangeToV(ctrl.hoveredHistoryRange.toV)
|
||||||
|
} else if (boundary === 'fromV') {
|
||||||
|
ctrl.setRangeFromV(ctrl.hoveredHistoryRange.fromV)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.isDragging = false
|
||||||
|
ctrl.resetHoveredRange()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ctrl.onDrop = (boundary, versionWithLabel) => {
|
||||||
|
if (boundary === 'toV') {
|
||||||
|
$scope.$applyAsync(() => ctrl.setRangeToV(versionWithLabel.version))
|
||||||
|
} else if (boundary === 'fromV') {
|
||||||
|
$scope.$applyAsync(() => ctrl.setRangeFromV(versionWithLabel.version))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.onOver = (boundary, versionWithLabel) => {
|
||||||
|
if (boundary === 'toV') {
|
||||||
|
$scope.$applyAsync(() =>
|
||||||
|
ctrl.setHoveredRangeToV(versionWithLabel.version)
|
||||||
|
)
|
||||||
|
} else if (boundary === 'fromV') {
|
||||||
|
$scope.$applyAsync(() =>
|
||||||
|
ctrl.setHoveredRangeFromV(versionWithLabel.version)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.handleVersionSelect = versionWithLabel => {
|
||||||
|
if (ctrl.rangeSelectionEnabled) {
|
||||||
|
// TODO
|
||||||
|
ctrl.onRangeSelect({
|
||||||
|
selectedToV: versionWithLabel.version,
|
||||||
|
selectedFromV: versionWithLabel.version
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ctrl.onVersionSelect({ version: versionWithLabel.version })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.setRangeToV = version => {
|
||||||
|
if (version >= ctrl.selectedHistoryRange.fromV) {
|
||||||
|
ctrl.onRangeSelect({
|
||||||
|
selectedToV: version,
|
||||||
|
selectedFromV: ctrl.selectedHistoryRange.fromV
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctrl.setRangeFromV = version => {
|
||||||
|
if (version <= ctrl.selectedHistoryRange.toV) {
|
||||||
|
ctrl.onRangeSelect({
|
||||||
|
selectedToV: ctrl.selectedHistoryRange.toV,
|
||||||
|
selectedFromV: version
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
// This method (and maybe the one below) will be removed soon. User details data will be
|
// This method (and maybe the one below) will be removed soon. User details data will be
|
||||||
// injected into the history API responses, so we won't need to fetch user data from other
|
// injected into the history API responses, so we won't need to fetch user data from other
|
||||||
// local data structures.
|
// local data structures.
|
||||||
|
@ -28,30 +145,37 @@ define([
|
||||||
return curUserId === id
|
return curUserId === id
|
||||||
})
|
})
|
||||||
ctrl.displayName = displayNameForUser
|
ctrl.displayName = displayNameForUser
|
||||||
ctrl.getUserCSSStyle = function(user, label) {
|
ctrl.getUserCSSStyle = function(user, versionWithLabel) {
|
||||||
const curUserId =
|
const curUserId =
|
||||||
(user != null ? user._id : undefined) ||
|
(user != null ? user._id : undefined) ||
|
||||||
(user != null ? user.id : undefined)
|
(user != null ? user.id : undefined)
|
||||||
const hue = ColorManager.getHueForUserId(curUserId) || 100
|
const hue = ColorManager.getHueForUserId(curUserId) || 100
|
||||||
if (
|
if (
|
||||||
label.id ===
|
ctrl.isVersionSelected(versionWithLabel.version) ||
|
||||||
(ctrl.selectedLabel != null ? ctrl.selectedLabel.id : undefined)
|
ctrl.isVersionHoverSelected(versionWithLabel.version)
|
||||||
) {
|
) {
|
||||||
return { color: '#FFF' }
|
return { color: '#FFF' }
|
||||||
} else {
|
} else {
|
||||||
return { color: `hsl(${hue}, 70%, 50%)` }
|
return { color: `hsl(${hue}, 70%, 50%)` }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctrl.$onInit = () => {
|
||||||
|
ctrl.resetHoveredRange()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return App.component('historyLabelsList', {
|
return App.component('historyLabelsList', {
|
||||||
bindings: {
|
bindings: {
|
||||||
labels: '<',
|
labels: '<',
|
||||||
|
rangeSelectionEnabled: '<',
|
||||||
users: '<',
|
users: '<',
|
||||||
currentUser: '<',
|
currentUser: '<',
|
||||||
isLoading: '<',
|
isLoading: '<',
|
||||||
selectedLabel: '<',
|
selectedHistoryVersion: '<?',
|
||||||
onLabelSelect: '&',
|
selectedHistoryRange: '<?',
|
||||||
|
onVersionSelect: '&',
|
||||||
|
onRangeSelect: '&',
|
||||||
onLabelDelete: '&'
|
onLabelDelete: '&'
|
||||||
},
|
},
|
||||||
controller: historyLabelsListController,
|
controller: historyLabelsListController,
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
/* eslint-disable
|
|
||||||
camelcase,
|
|
||||||
max-len,
|
|
||||||
no-return-assign,
|
|
||||||
no-undef,
|
|
||||||
*/
|
|
||||||
define(['base', 'ide/history/util/displayNameForUser'], function(
|
|
||||||
App,
|
|
||||||
displayNameForUser
|
|
||||||
) {
|
|
||||||
App.controller('HistoryCompareController', [
|
|
||||||
'$scope',
|
|
||||||
'$modal',
|
|
||||||
'ide',
|
|
||||||
'_',
|
|
||||||
function($scope, $modal, ide, _) {
|
|
||||||
$scope.projectUsers = []
|
|
||||||
$scope.versionsWithLabels = []
|
|
||||||
|
|
||||||
$scope.$watch('project.members', function(newVal) {
|
|
||||||
if (newVal != null) {
|
|
||||||
$scope.projectUsers = newVal.concat($scope.project.owner)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
$scope.$watchCollection('history.labels', function(labels) {
|
|
||||||
if (labels != null && labels.length > 0) {
|
|
||||||
const groupedLabelsHash = _.groupBy(labels, 'version')
|
|
||||||
$scope.versionsWithLabels = _.map(
|
|
||||||
groupedLabelsHash,
|
|
||||||
(labels, version) => {
|
|
||||||
return {
|
|
||||||
version: parseInt(version, 10),
|
|
||||||
labels
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
$scope.loadMore = () => ide.historyManager.fetchNextBatchOfUpdates()
|
|
||||||
|
|
||||||
$scope.setHoverFrom = fromV => ide.historyManager.setHoverFrom(fromV)
|
|
||||||
|
|
||||||
$scope.setHoverTo = toV => ide.historyManager.setHoverTo(toV)
|
|
||||||
|
|
||||||
$scope.resetHover = () => ide.historyManager.resetHover()
|
|
||||||
|
|
||||||
$scope.select = (toV, fromV) => {
|
|
||||||
$scope.history.selection.range.toV = toV
|
|
||||||
$scope.history.selection.range.fromV = fromV
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.addLabelVersionToSelection = version => {
|
|
||||||
ide.historyManager.expandSelectionToVersion(version)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method (and maybe the one below) will be removed soon. User details data will be
|
|
||||||
// injected into the history API responses, so we won't need to fetch user data from other
|
|
||||||
// local data structures.
|
|
||||||
$scope.getUserById = id =>
|
|
||||||
_.find($scope.projectUsers, function(user) {
|
|
||||||
let curUserId
|
|
||||||
if (user) {
|
|
||||||
curUserId = user._id || user.id
|
|
||||||
}
|
|
||||||
return curUserId === id
|
|
||||||
})
|
|
||||||
|
|
||||||
$scope.getDisplayNameById = id =>
|
|
||||||
displayNameForUser($scope.getUserById(id))
|
|
||||||
|
|
||||||
$scope.getDisplayNameForUser = user => displayNameForUser(user)
|
|
||||||
|
|
||||||
$scope.deleteLabel = labelDetails =>
|
|
||||||
$modal.open({
|
|
||||||
templateUrl: 'historyV2DeleteLabelModalTemplate',
|
|
||||||
controller: 'HistoryV2DeleteLabelModalController',
|
|
||||||
resolve: {
|
|
||||||
labelDetails() {
|
|
||||||
return labelDetails
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
])
|
|
||||||
})
|
|
|
@ -35,11 +35,18 @@ define(['base', 'ide/history/util/displayNameForUser'], (
|
||||||
return ide.historyManager.fetchNextBatchOfUpdates()
|
return ide.historyManager.fetchNextBatchOfUpdates()
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.handleEntrySelect = entry =>
|
$scope.handleVersionSelect = version =>
|
||||||
ide.historyManager.selectVersionForPointInTime(entry.toV)
|
$scope.$applyAsync(() =>
|
||||||
|
ide.historyManager.selectVersionForPointInTime(version)
|
||||||
|
)
|
||||||
|
|
||||||
$scope.handleLabelSelect = label =>
|
$scope.handleRangeSelect = (selectedToV, selectedFromV) =>
|
||||||
ide.historyManager.selectLabelForPointInTime(label)
|
$scope.$applyAsync(() =>
|
||||||
|
ide.historyManager.selectVersionsForCompare(
|
||||||
|
selectedToV,
|
||||||
|
selectedFromV
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return ($scope.handleLabelDelete = labelDetails =>
|
return ($scope.handleLabelDelete = labelDetails =>
|
||||||
$modal.open({
|
$modal.open({
|
||||||
|
|
|
@ -21,6 +21,9 @@ define(['base'], App =>
|
||||||
($scope, $modal, ide, event_tracking, waitFor) => {
|
($scope, $modal, ide, event_tracking, waitFor) => {
|
||||||
let openEntity
|
let openEntity
|
||||||
|
|
||||||
|
$scope.currentUpdate = null
|
||||||
|
$scope.currentLabel = null
|
||||||
|
|
||||||
$scope.restoreState = {
|
$scope.restoreState = {
|
||||||
inflight: false,
|
inflight: false,
|
||||||
error: false
|
error: false
|
||||||
|
@ -50,6 +53,22 @@ define(['base'], App =>
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$scope.$watch('history.viewMode', (newVal, oldVal) => {
|
||||||
|
if (newVal != null && newVal !== oldVal) {
|
||||||
|
$scope.currentUpdate = ide.historyManager.getUpdateForVersion(newVal)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
$scope.$watch('history.selection.range.toV', (newVal, oldVal) => {
|
||||||
|
if (
|
||||||
|
newVal != null &&
|
||||||
|
newVal !== oldVal &&
|
||||||
|
$scope.history.viewMode === $scope.HistoryViewModes.POINT_IN_TIME
|
||||||
|
) {
|
||||||
|
$scope.currentUpdate = ide.historyManager.getUpdateForVersion(newVal)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
$scope.toggleHistoryViewMode = () => {
|
$scope.toggleHistoryViewMode = () => {
|
||||||
ide.historyManager.toggleHistoryViewMode()
|
ide.historyManager.toggleHistoryViewMode()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
define(['base'], App =>
|
||||||
|
App.directive('historyDraggableBoundary', () => ({
|
||||||
|
scope: {
|
||||||
|
historyDraggableBoundary: '@',
|
||||||
|
historyDraggableBoundaryOnDragStart: '&',
|
||||||
|
historyDraggableBoundaryOnDragStop: '&'
|
||||||
|
},
|
||||||
|
restrict: 'A',
|
||||||
|
link(scope, element, attrs) {
|
||||||
|
element.data('selectionBoundary', {
|
||||||
|
boundary: scope.historyDraggableBoundary
|
||||||
|
})
|
||||||
|
element.draggable({
|
||||||
|
axis: 'y',
|
||||||
|
opacity: false,
|
||||||
|
helper: 'clone',
|
||||||
|
revert: true,
|
||||||
|
scroll: true,
|
||||||
|
cursor: 'row-resize',
|
||||||
|
start(e, ui) {
|
||||||
|
ui.helper.data('wasProperlyDropped', false)
|
||||||
|
scope.historyDraggableBoundaryOnDragStart()
|
||||||
|
},
|
||||||
|
stop(e, ui) {
|
||||||
|
scope.historyDraggableBoundaryOnDragStop({
|
||||||
|
isValidDrop: ui.helper.data('wasProperlyDropped'),
|
||||||
|
boundary: scope.historyDraggableBoundary
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})))
|
|
@ -0,0 +1,25 @@
|
||||||
|
define(['base'], App =>
|
||||||
|
App.directive('historyDroppableArea', () => ({
|
||||||
|
scope: {
|
||||||
|
historyDroppableAreaOnDrop: '&',
|
||||||
|
historyDroppableAreaOnOver: '&',
|
||||||
|
historyDroppableAreaOnOut: '&'
|
||||||
|
},
|
||||||
|
restrict: 'A',
|
||||||
|
link(scope, element, attrs) {
|
||||||
|
element.droppable({
|
||||||
|
accept: e => '.history-entry-toV-handle, .history-entry-fromV-handle',
|
||||||
|
drop: (e, ui) => {
|
||||||
|
const draggedBoundary = ui.draggable.data('selectionBoundary')
|
||||||
|
.boundary
|
||||||
|
ui.helper.data('wasProperlyDropped', true)
|
||||||
|
scope.historyDroppableAreaOnDrop({ boundary: draggedBoundary })
|
||||||
|
},
|
||||||
|
over: (e, ui) => {
|
||||||
|
const draggedBoundary = ui.draggable.data('selectionBoundary')
|
||||||
|
.boundary
|
||||||
|
scope.historyDroppableAreaOnOver({ boundary: draggedBoundary })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})))
|
|
@ -69,6 +69,10 @@
|
||||||
color: @history-base-color;
|
color: @history-base-color;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: @history-base-bg;
|
background-color: @history-base-bg;
|
||||||
|
position: relative;
|
||||||
|
&.history-entries-dragging {
|
||||||
|
cursor: row-resize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.history-entry-day {
|
.history-entry-day {
|
||||||
|
@ -79,18 +83,82 @@
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.history-entry-toV-handle,
|
||||||
|
.history-entry-fromV-handle {
|
||||||
|
position: absolute;
|
||||||
|
background-color: @history-entry-handle-bg;
|
||||||
|
height: @history-entry-handle-height;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 2;
|
||||||
|
cursor: row-resize;
|
||||||
|
|
||||||
|
&.ui-draggable-dragging {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '\00b7\00b7\00b7\00b7';
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #FFF;
|
||||||
|
height: @history-entry-handle-height;
|
||||||
|
line-height: @history-entry-handle-height / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-entry-fromV-handle {
|
||||||
|
top: auto;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.history-entry-details {
|
.history-entry-details {
|
||||||
|
position: relative;
|
||||||
background-color: #FFF;
|
background-color: #FFF;
|
||||||
margin-bottom: 2px;
|
border-bottom: solid 2px @history-base-bg;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.history-entry-selected &,
|
.history-version-with-label {
|
||||||
.history-entry-label-selected & {
|
.history-entry-details;
|
||||||
|
padding: 7px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-entry-selected .history-entry-details,
|
||||||
|
.history-version-with-label-selected & {
|
||||||
background-color: @history-entry-selected-bg;
|
background-color: @history-entry-selected-bg;
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.history-entry-hover-selected .history-entry-details,
|
||||||
|
.history-entry-hover-selected.history-entry-selected .history-entry-details,
|
||||||
|
.history-version-with-label-hover-selected &,
|
||||||
|
.history-version-with-label-hover-selected.history-entry-selected &, {
|
||||||
|
background-color: tint(@history-entry-selected-bg, 20%);
|
||||||
|
color: #FFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.history-entry-selected-to .history-entry-details,
|
||||||
|
.history-entry-hover-selected-to .history-entry-details,
|
||||||
|
.history-version-with-label-selected-to &,
|
||||||
|
.history-version-with-label-hover-selected-to & {
|
||||||
|
padding-top: @history-entry-handle-height + 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-entry-selected-from .history-entry-details,
|
||||||
|
.history-entry-hover-selected-from .history-entry-details,
|
||||||
|
.history-version-with-label-selected-from &,
|
||||||
|
.history-version-with-label-hover-selected-from & {
|
||||||
|
padding-bottom: @history-entry-handle-height + 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.history-label {
|
.history-label {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
color: @history-entry-label-color;
|
color: @history-entry-label-color;
|
||||||
|
@ -99,12 +167,16 @@
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
.history-entry-selected &,
|
.history-entry-selected &,
|
||||||
.history-entry-label-selected & {
|
.history-entry-hover-selected &,
|
||||||
|
.history-version-with-label-selected &,
|
||||||
|
.history-version-with-label-hover-selected & {
|
||||||
color: @history-entry-selected-label-color;
|
color: @history-entry-selected-label-color;
|
||||||
}
|
}
|
||||||
&.history-label-pseudo-current-state {
|
&.history-label-pseudo-current-state {
|
||||||
.history-entry-selected &,
|
.history-entry-selected &,
|
||||||
.history-entry-label-selected & {
|
.history-entry-hover-selected &,
|
||||||
|
.history-version-with-label-selected &,
|
||||||
|
.history-version-with-label-hover-selected & {
|
||||||
color: @history-entry-selected-pseudo-label-color;
|
color: @history-entry-selected-pseudo-label-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +191,9 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
.history-entry-selected &,
|
.history-entry-selected &,
|
||||||
.history-entry-label-selected & {
|
.history-entry-hover-selected &,
|
||||||
|
.history-version-with-label-selected &,
|
||||||
|
.history-version-with-label-hover-selected & {
|
||||||
background-color: @history-entry-selected-label-bg-color;
|
background-color: @history-entry-selected-label-bg-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +216,9 @@
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: darken(@history-entry-label-bg-color, 8%);
|
background-color: darken(@history-entry-label-bg-color, 8%);
|
||||||
.history-entry-selected &,
|
.history-entry-selected &,
|
||||||
.history-entry-label-selected & {
|
.history-entry-hover-selected &,
|
||||||
|
.history-version-with-label-selected &,
|
||||||
|
.history-version-with-label-hover-selected & {
|
||||||
background-color: darken(@history-entry-selected-label-bg-color, 8%);
|
background-color: darken(@history-entry-selected-label-bg-color, 8%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,7 +257,8 @@
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
.history-entry-selected &,
|
.history-entry-selected &,
|
||||||
.history-entry-label-selected & {
|
.history-entry-hover-selected &,
|
||||||
|
.history-version-with-label-selected & {
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,14 +300,6 @@
|
||||||
.history-labels-list-compare {
|
.history-labels-list-compare {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
.history-entry-label {
|
|
||||||
.history-entry-details;
|
|
||||||
padding: 7px 10px;
|
|
||||||
&.history-entry-label-selected {
|
|
||||||
background-color: @history-entry-selected-bg;
|
|
||||||
color: #FFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.history-file-tree-inner {
|
.history-file-tree-inner {
|
||||||
.full-size;
|
.full-size;
|
||||||
|
|
|
@ -1030,6 +1030,8 @@
|
||||||
@history-entry-selected-pseudo-label-color: @green;
|
@history-entry-selected-pseudo-label-color: @green;
|
||||||
@history-entry-day-bg : @gray;
|
@history-entry-day-bg : @gray;
|
||||||
@history-entry-selected-bg : @red;
|
@history-entry-selected-bg : @red;
|
||||||
|
@history-entry-handle-bg : darken(@history-entry-selected-bg, 10%);
|
||||||
|
@history-entry-handle-height : 8px;
|
||||||
@history-base-color : @gray-light;
|
@history-base-color : @gray-light;
|
||||||
@history-highlight-color : @gray;
|
@history-highlight-color : @gray;
|
||||||
@history-toolbar-bg-color : @toolbar-alt-bg-color;
|
@history-toolbar-bg-color : @toolbar-alt-bg-color;
|
||||||
|
|
|
@ -346,6 +346,8 @@
|
||||||
@history-entry-selected-pseudo-label-color: @ol-green;
|
@history-entry-selected-pseudo-label-color: @ol-green;
|
||||||
@history-entry-day-bg : @ol-blue-gray-2;
|
@history-entry-day-bg : @ol-blue-gray-2;
|
||||||
@history-entry-selected-bg : @ol-green;
|
@history-entry-selected-bg : @ol-green;
|
||||||
|
@history-entry-handle-bg : darken(@ol-green, 10%);
|
||||||
|
@history-entry-handle-height : 8px;
|
||||||
@history-base-color : @ol-blue-gray-2;
|
@history-base-color : @ol-blue-gray-2;
|
||||||
@history-highlight-color : @ol-type-color;
|
@history-highlight-color : @ol-type-color;
|
||||||
@history-toolbar-bg-color : @editor-toolbar-bg;
|
@history-toolbar-bg-color : @editor-toolbar-bg;
|
||||||
|
|
|
@ -34,8 +34,6 @@ define(['ide/history/HistoryV2Manager'], HistoryV2Manager =>
|
||||||
},
|
},
|
||||||
diff: null,
|
diff: null,
|
||||||
files: [],
|
files: [],
|
||||||
update: null,
|
|
||||||
label: null,
|
|
||||||
file: null
|
file: null
|
||||||
},
|
},
|
||||||
error: null,
|
error: null,
|
||||||
|
|
Loading…
Reference in a new issue