Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
07591c7
add History Activity for projects
LrxGaelle May 7, 2026
f89307f
add icons for ProjectOverview tabs
LrxGaelle May 7, 2026
96befe4
add click to path
LrxGaelle May 7, 2026
017d094
delete unused style
LrxGaelle May 7, 2026
d2c666c
delete unused darktheme ds config
LrxGaelle May 7, 2026
2a5c3dc
add translation
LrxGaelle May 7, 2026
e87af58
fix detail-path height
LrxGaelle May 7, 2026
7a1d1a3
fix ActivityItem style
LrxGaelle May 18, 2026
ae4236f
delete unnecessary async
LrxGaelle May 18, 2026
8c554ca
Added styling to the main tabs of the project overview.
LrxGaelle May 18, 2026
7713147
move activity-config into src/config folder
LrxGaelle May 18, 2026
0ccc54a
change translation
LrxGaelle May 18, 2026
36ce65d
add searchbar
LrxGaelle May 18, 2026
060c24e
delete empty title
LrxGaelle May 18, 2026
c71dca2
add en translations
LrxGaelle May 18, 2026
f2ca091
Add ProjectOverview title
LrxGaelle May 20, 2026
bee8d39
remove folder_permissions_updated pending API improvements
LrxGaelle May 21, 2026
8515a84
add bimdata textbox for activity target
LrxGaelle May 21, 2026
25c1f73
add date
LrxGaelle May 21, 2026
9f84983
disable user-select for activity item title
LrxGaelle May 21, 2026
9424b4b
display notifications & history for admin only
LrxGaelle May 22, 2026
90b1156
add empty state for history activity
LrxGaelle May 22, 2026
fe94e91
fix notifications panel height
LrxGaelle May 22, 2026
bec9177
sync logs on project change and fix empty state check
LrxGaelle May 22, 2026
91f55c7
fix go to GED view for history activity
LrxGaelle May 22, 2026
9817c03
fix detail style
LrxGaelle May 22, 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
6 changes: 4 additions & 2 deletions src/components/specific/files/files-manager/FilesManager.vue
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ export default {
if (selectedFileTab.value.id === "folders") {
// WARNING displayedRows is name from DS, may change
const folderFiles = filesTable.value.filesTable.displayedRows.map((row) => row.data);
documentList = folderFiles.filter(f => !isFolder(f));
documentList = folderFiles.filter((f) => !isFolder(f));
}
if (selectedFileTab.value.id === "files") {
documentList = filesTable.value.displayedListFiles;
Expand Down Expand Up @@ -663,11 +663,13 @@ export default {

onActivated(() => {
const folderId = gedTargetFolder.get();

if (folderId) {
jumpToTargetFolder(folderId);
jumpToTargetFolder(folderId, true);
} else {
jumpToTargetFolder(props.fileStructure.id);
}

gedTargetFolder.clear();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<ModelTagsCell :model="model" :parent="modelsTable" />
</template>
<template #cell-location="{ row: model }">
<div class="visas-table__location">
<div class="models-table__location">
<ModelPathCell
:model="model"
:allFolders="allFolders"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
maxWidth="200px"
/>
</div>

<transition name="fade">
<div v-if="hovering || showFullPath" class="model-path-cell__location">
<div
Expand Down Expand Up @@ -57,21 +57,15 @@
<BIMDataIconChevron size="xxxs" fill color="default" />
</div>
</div>

<span
v-else
class="folder-name flex items-center"
@click.stop="goToGedRoot"
>

<span v-else class="folder-name flex items-center" @click.stop="goToGedRoot">
<BIMDataIconFolderLocation fill color="primary" margin="0 6px 0 0" />
{{ $t("t.rootFolder") }}
</span>
</div>
</transition>
</template>
<template v-else>
-
</template>
<template v-else> - </template>
</div>
</template>

Expand Down Expand Up @@ -102,7 +96,7 @@ export default {
const hovering = ref(false);
const showFullPath = ref(false);
const hasLocation = computed(
() => ![MODEL_TYPE.META_BUILDING, MODEL_TYPE.PHOTOSPHERE_BUILDING].includes(props.model.type)
() => ![MODEL_TYPE.META_BUILDING, MODEL_TYPE.PHOTOSPHERE_BUILDING].includes(props.model.type),
);

const folderLocation = (model) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.history-activity-panel {
height: calc(100vh - 44px - 40px - 12px - 12px);
overflow: auto;
.header {
h3 {
margin-bottom: 12px;
font-size: 18px;
}
}
.input-search {
border: 1px solid transparent;
border-radius: 3px;
&.focus {
background-color: var(--color-silver-light);
box-shadow: none;
border: 1px solid #efefef;
}
}
.day-group {
margin-top: 20px;
.day-title {
font-size: 13px;
color: var(--color-granite);
margin-bottom: 8px;
font-weight: 600;
}

}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<template>
<div class="history-activity-panel">
<div class="header">
<h3>{{ $t("ProjectOverview.activity.title") }}</h3>
</div>

<BIMDataSearch
class="input-search"
width="95%"
:placeholder="$t('t.search')"
v-model="searchText"
clear
color="primary"
/>

<template v-if="hasDisplayedLogs">
<div v-for="(logs, day) in displayedGroupedLogs" :key="day" class="day-group">
<div class="day-title">{{ day }}</div>
<ActivityItem
v-for="log in logs"
:key="log.id"
:log="log"
:formatTimeAgo="formatTimeAgo"
@go-folder="$emit('go-folder', $event)"
/>
</div>
</template>
<template v-else>
<p>{{ $t("ProjectOverview.activity.empty") }}</p>
</template>
</div>
</template>

<script>
import { ref, onMounted, computed, watch } from "vue";
import { useI18n } from "vue-i18n";

import { getActivityFromLog } from "../../../../config/activity-config.js";
import { useTimeAgo } from "../../../../composables/time.js";
import ProjectService from "../../../../services/ProjectService.js";

import ActivityItem from "./activity-item/ActivityItem.vue";

export default {
props: {
project: Object,
},
components: {
ActivityItem,
},
emits: ["go-folder"],

setup(props) {
const { t, locale } = useI18n();

const logs = ref([]);
const searchText = ref("");

const { formatTimeAgo } = useTimeAgo();

const fetchLogs = async () => {
logs.value = [];

const fetchedLogs = await ProjectService.fetchLogs(props.project);

logs.value = fetchedLogs
.map((log) => {
const activity = getActivityFromLog(log);

if (!activity) return null;

return {
...log,
activity,
dateObj: new Date(log.date),

_search: [
log.action,
log.user_email,
log.project_name,
activity?.target,
log.path,
t(activity?.actionKey ?? ""),
]
.filter(Boolean)
.join(" ")
.toLowerCase(),
};
})
.filter(Boolean);
};

onMounted(fetchLogs);

watch(() => props.project, fetchLogs);

const formatDay = (date) => {
const today = new Date();
const yesterday = new Date();

yesterday.setDate(today.getDate() - 1);

if (date.toDateString() === today.toDateString()) {
return t("t.today");
}

if (date.toDateString() === yesterday.toDateString()) {
return t("t.yesterday");
}

return date.toLocaleDateString(locale.value, {
day: "numeric",
month: "long",
year: "numeric",
});
};

const sortedLogs = computed(() => logs.value.slice().sort((a, b) => b.dateObj - a.dateObj));

const displayedGroupedLogs = computed(() => {
const search = searchText.value.trim().toLowerCase();

return sortedLogs.value
.filter((log) => !search || log._search.includes(search))
.reduce((groups, log) => {
const day = formatDay(log.dateObj);

groups[day] ??= [];
groups[day].push(log);

return groups;
}, {});
});
const hasDisplayedLogs = computed(() => Object.keys(displayedGroupedLogs.value).length > 0);

return {
displayedGroupedLogs,
hasDisplayedLogs,
searchText,
formatTimeAgo,
};
},
};
</script>

<style scoped src="./ProjectHistoryActivity.css"></style>
Loading
Loading