Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e48744e
[hardware-items] Migrate page to Composition API
frankrousseau Apr 29, 2026
81fddb9
[software-licenses] Migrate page to Composition API
frankrousseau Apr 29, 2026
53af85e
[budget] Migrate SalaryScale page to Composition API
frankrousseau Apr 30, 2026
d262d40
[hardware-items] Convert list to Composition API
frankrousseau Apr 30, 2026
e941191
[software-licenses] Convert list to Composition API
frankrousseau Apr 30, 2026
4222866
[studios] Apply Composition API cleanup
frankrousseau Apr 30, 2026
aaa8405
[departments] Migrate page to Composition API
frankrousseau Apr 30, 2026
2a7b892
[departments] Convert list to Composition API
frankrousseau Apr 30, 2026
6f715d5
[layouts] Convert PageLayout and PageLeftSideLayout to Composition API
frankrousseau May 1, 2026
23680ad
[cells] Convert cells to Composition API
frankrousseau May 1, 2026
0a4db79
[composables] Add useFormat composable, migrate ValidationCell
frankrousseau May 1, 2026
ded4b9f
[modals] Convert BaseModal-using modals to Composition API
frankrousseau May 1, 2026
c499d92
[modals] Convert small admin-edit modals to Composition API
frankrousseau May 1, 2026
1dd1a19
[modals] Drop dead CSS in BaseModal-using modals
frankrousseau May 1, 2026
c9714db
[modals] Convert asset-type / background / episode / sequence modals
frankrousseau May 1, 2026
bc6932b
[modals] Convert task-status / task-type / day-off / change-password …
frankrousseau May 1, 2026
538f161
[modals] Convert edit / history / search-filter modals
frankrousseau May 1, 2026
645ec65
[modals] Convert import / history / shortcut modals
frankrousseau May 1, 2026
1d95c75
[modals] Convert avatar / preview / select-task-type modals
frankrousseau May 1, 2026
4bf2c91
[modals] Convert set-frames / token / create-tasks / playlist modals
frankrousseau May 1, 2026
2c7f54d
[modals] Convert add-attachment / thumbnails / edit-shot / edit-asset
frankrousseau May 1, 2026
5c0a24c
[modals] Convert build-people-filter / view-playlist / add-preview
frankrousseau May 2, 2026
9d16c2d
[modals] Convert manage-shots / import-render modals
frankrousseau May 2, 2026
7b5c3e2
[modals] Convert edit-comment / edit-person modals
frankrousseau May 2, 2026
2bfd99e
[modals] Convert BuildFilterModal to Composition API
frankrousseau May 2, 2026
5825a80
[cells] Hide number-input spinners in MetadataInput
frankrousseau May 4, 2026
c329b2f
[modals] Expose missing methods on AddAttachment / AddPreview
frankrousseau May 4, 2026
68d5a52
[datatable] Fix z-index hierarchy so headers stay above body cells
frankrousseau May 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -1649,7 +1649,17 @@ tbody:last-child .empty-line:last-child {
text-transform: uppercase;
top: 0;
vertical-align: middle;
z-index: 2;
// Header z-index hierarchy is built around the body taglist metadata
// cells which bump their own z-index up to 1000 so the open combo
// dropdown can spill over the next row (see td.metadata-descriptor
// inline z-index in AssetList.vue / ShotList.vue):
// body taglist ≤ 1000
// body sticky-left 1001 (.datatable-row-header)
// header non-sticky 1002 (this rule)
// header sticky-left 1003 (.datatable-head .datatable-row-header)
// The +1 between body sticky-left and header non-sticky breaks the
// document-order tie at the vertical-scroll seam.
z-index: 1002;

a {
color: var(--text-alt);
Expand Down Expand Up @@ -1700,7 +1710,7 @@ tbody:last-child .empty-line:last-child {
}

.datatable-row-header {
z-index: 4;
z-index: 1003;
}
.header-icon {
visibility: hidden;
Expand Down Expand Up @@ -1894,7 +1904,7 @@ tbody:last-child .empty-line:last-child {
.datatable-row-header {
position: sticky;
left: 0;
z-index: 1;
z-index: 1001;
border-right: 1px solid rgba(var(--border-rgb), 0.5);

&::after {
Expand Down
19 changes: 4 additions & 15 deletions src/components/cells/BooleanCell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,12 @@
</td>
</template>

<script>
<script setup>
import BooleanRep from '@/components/widgets/BooleanRep.vue'

export default {
name: 'boolean-cell',

components: {
BooleanRep
},

props: {
value: {
default: false,
type: Boolean
}
}
}
defineProps({
value: { type: Boolean, default: false }
})
</script>

<style lang="scss" scoped>
Expand Down
40 changes: 15 additions & 25 deletions src/components/cells/DepartmentNamesCell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,27 @@
</td>
</template>

<script>
import { mapGetters } from 'vuex'
<script setup>
import { computed } from 'vue'
import { useStore } from 'vuex'

import { sortByName } from '@/lib/sorting'

import DepartmentName from '@/components/widgets/DepartmentName.vue'

export default {
name: 'department-names-cell',
const store = useStore()

components: {
DepartmentName
},
const props = defineProps({
departments: { type: Array, default: () => [] }
})

props: {
departments: {
type: Array,
default: () => []
}
},
const departmentMap = computed(() => store.getters.departmentMap)

computed: {
...mapGetters(['departmentMap']),

sortedDepartments() {
return sortByName(
this.departments
.map(departmentId => this.departmentMap.get(departmentId))
.filter(Boolean)
)
}
}
}
const sortedDepartments = computed(() =>
sortByName(
props.departments
.map(departmentId => departmentMap.value.get(departmentId))
.filter(Boolean)
)
)
</script>
143 changes: 59 additions & 84 deletions src/components/cells/DescriptionCell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,98 +47,73 @@
</td>
</template>

<script>
import { mapGetters } from 'vuex'
<script setup>
import { computed, nextTick, ref } from 'vue'
import { useStore } from 'vuex'

import { renderMarkdown } from '@/lib/render'
import stringHelpers from '@/lib/string'

export default {
name: 'description-cell',

data() {
return {
isEditing: false,
isOpen: false,
tooltipPosition: { top: 0, left: 0 }
}
},

props: {
editable: {
type: Boolean,
default: false
},
entry: {
type: Object,
default: () => {}
},
full: {
type: Boolean,
default: false
}
},

emits: ['description-changed'],

computed: {
...mapGetters(['isDarkTheme']),

tooltipStyle() {
return {
top: this.tooltipPosition.top + 'px',
left: this.tooltipPosition.left + 'px'
}
}
},

methods: {
renderMarkdown,

shortenText: stringHelpers.shortenText,

onClick(event) {
if (
(event.currentTarget.classList.contains('description-cell') &&
!event.target.closest('.description-cell .tooltip')) ||
event.keyCode === 27
) {
this.isOpen = !this.isOpen
if (this.isOpen) {
const td = event.currentTarget
const rect = td.getBoundingClientRect()
const scrollTop =
window.pageYOffset || document.documentElement.scrollTop
const scrollLeft =
window.pageXOffset || document.documentElement.scrollLeft
this.tooltipPosition = {
top: rect.top + scrollTop - 105,
left: rect.left + scrollLeft + rect.width / 2 - 160
}
} else if (this.isEditing) {
this.isEditing = false
const val = this.$refs.text.value
this.$emit('description-changed', val)
}
}
},

onDoubleClick() {
if (this.editable) {
if (this.isEditing) {
const val = this.$refs.text.value
this.$emit('description-changed', val)
}
this.isEditing = !this.isEditing
if (this.isEditing) {
this.$nextTick(() => {
this.$refs.text.focus()
})
}
const store = useStore()

const props = defineProps({
editable: { type: Boolean, default: false },
entry: { type: Object, default: () => ({}) },
full: { type: Boolean, default: false }
})

const emit = defineEmits(['description-changed'])

const isDarkTheme = computed(() => store.getters.isDarkTheme)

const isEditing = ref(false)
const isOpen = ref(false)
const text = ref(null)
const tooltipPosition = ref({ top: 0, left: 0 })

const tooltipStyle = computed(() => ({
top: tooltipPosition.value.top + 'px',
left: tooltipPosition.value.left + 'px'
}))

const shortenText = stringHelpers.shortenText

const onClick = event => {
if (
(event.currentTarget.classList.contains('description-cell') &&
!event.target.closest('.description-cell .tooltip')) ||
event.keyCode === 27
) {
isOpen.value = !isOpen.value
if (isOpen.value) {
const td = event.currentTarget
const rect = td.getBoundingClientRect()
const scrollTop = window.pageYOffset || document.documentElement.scrollTop
const scrollLeft =
window.pageXOffset || document.documentElement.scrollLeft
tooltipPosition.value = {
top: rect.top + scrollTop - 105,
left: rect.left + scrollLeft + rect.width / 2 - 160
}
} else if (isEditing.value) {
isEditing.value = false
emit('description-changed', text.value.value)
}
}
}

const onDoubleClick = () => {
if (!props.editable) return
if (isEditing.value) {
emit('description-changed', text.value.value)
}
isEditing.value = !isEditing.value
if (isEditing.value) {
nextTick(() => {
text.value.focus()
})
}
}
</script>

<style lang="scss" scoped>
Expand Down
50 changes: 13 additions & 37 deletions src/components/cells/LastCommentCell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,49 +27,25 @@
</td>
</template>

<script>
<script setup>
import { computed } from 'vue'

import { renderMarkdown } from '@/lib/render'

import PeopleAvatar from '@/components/widgets/PeopleAvatar.vue'

export default {
name: 'last-comment-cell',

emits: ['click'],

components: {
PeopleAvatar
},
const props = defineProps({
task: { type: Object, required: true }
})

data() {
return {
timeout: null
}
},
defineEmits(['click'])

props: {
task: {
type: Object,
required: true
}
},

computed: {
commentText() {
const text = this.task.last_comment.text
const maxLength = 140
let result = text || ''
if (text !== undefined && text.length > maxLength) {
result = text.slice(0, maxLength) + '...'
}
return result
}
},

methods: {
renderMarkdown
}
}
const commentText = computed(() => {
const text = props.task.last_comment.text
const maxLength = 140
if (text === undefined) return ''
return text.length > maxLength ? text.slice(0, maxLength) + '...' : text
})
</script>

<style lang="scss" scoped>
Expand Down
10 changes: 10 additions & 0 deletions src/components/cells/MetadataInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,16 @@ const onNumberFieldKeyDown = event => {
width: 1.15rem;
}

&[type='number'] {
-moz-appearance: textfield;

&::-webkit-inner-spin-button,
&::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
}

&:active,
&:focus,
&:hover {
Expand Down
20 changes: 4 additions & 16 deletions src/components/cells/PeopleNameCell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,13 @@
</td>
</template>

<script>
<script setup>
import PeopleAvatar from '@/components/widgets/PeopleAvatar.vue'
import PeopleName from '@/components/widgets/PeopleName.vue'

export default {
name: 'people-name-cell',

components: {
PeopleAvatar,
PeopleName
},

props: {
person: {
type: Object,
required: true
}
}
}
defineProps({
person: { type: Object, required: true }
})
</script>

<style lang="scss" scoped>
Expand Down
Loading
Loading