Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
0a48331
add rule manager
Amoki Jun 26, 2026
e8be79a
assing constraint to folders
Amoki Jun 29, 2026
5805052
improve UX
Amoki Jun 29, 2026
8e71eaa
improve rename modal
Amoki Jun 29, 2026
883d696
update lib & add modal when editing rule
Amoki Jul 1, 2026
4c97ffa
use css files instead of scss and separate style and template
LrxGaelle Jul 3, 2026
33025a1
fix css import
LrxGaelle Jul 3, 2026
7383e12
add some UI fix
LrxGaelle Jul 6, 2026
7842b59
add some fixs
LrxGaelle Jul 8, 2026
2aa12cc
fix delete actions menu
LrxGaelle Jul 9, 2026
b2797d7
fix delete constraint call
LrxGaelle Jul 9, 2026
c2f2c7e
refactor manager navigation with tabs
LrxGaelle Jul 9, 2026
07a1918
fixed footer action in constraint form
LrxGaelle Jul 9, 2026
d69a0f1
fix empty templates list view
LrxGaelle Jul 9, 2026
254ec0a
preserve rule state when creating naming templates
LrxGaelle Jul 9, 2026
066dfd0
validate required fields before saving a rule
LrxGaelle Jul 10, 2026
ee48630
Refactor and reorganize the style
LrxGaelle Jul 10, 2026
353b533
start fix naming conflict modal
LrxGaelle Jul 16, 2026
b6158af
add modal for stric & non-stric rule & add folder info icon
LrxGaelle Jul 21, 2026
5d4ab5f
Add some styles for hamonize & refactor and replace duplicated previ…
LrxGaelle Jul 21, 2026
7dd32da
fix restore correct navigation after constraint and template creation
LrxGaelle Jul 24, 2026
c9e1e17
fix autofocus newly added template element
LrxGaelle Jul 27, 2026
2dcbaed
clean up template creation navigation state
LrxGaelle Jul 27, 2026
80b5727
fix hasNamingConflict for folder
LrxGaelle Jul 27, 2026
90fdad5
refresh GED after naming constraint updates
LrxGaelle Jul 27, 2026
8eda451
add naming constraint editor for conflicting documents
LrxGaelle Jul 27, 2026
35e2ee1
delete dead code
LrxGaelle Jul 28, 2026
1e9219b
fix modal components style
LrxGaelle Jul 28, 2026
8621451
fix overflow
LrxGaelle Jul 28, 2026
32947f4
fix acutal name in conflict modal
LrxGaelle Jul 28, 2026
b29ee17
add translations
LrxGaelle Jul 28, 2026
d045560
add safeZoneModal when cancel NamingConstraintsForm
LrxGaelle Jul 29, 2026
a6cf965
refactor and move effective folder rule cache into NamingConstraintSe…
LrxGaelle Jul 29, 2026
285a4a0
add bulk import for naming template elements & add translations
LrxGaelle Jul 29, 2026
6d8dc91
delete unused translation key & add documents count on rename modal
LrxGaelle Jul 30, 2026
57b42bf
add v-show on openNamingConstraintsManager to display only, on folder…
LrxGaelle Jul 30, 2026
5cb3fa1
display naming constraint preview for folders
LrxGaelle Aug 11, 2026
8da9d95
fix folder rule selection and conflict notifications
LrxGaelle Aug 25, 2026
c8d6b9e
add current_key++ to menuItem
LrxGaelle Aug 25, 2026
6a26f86
handle separators inside list values
LrxGaelle Aug 25, 2026
ad977b6
fallback to global rule when document rule is missing
LrxGaelle Sep 24, 2026
8063a22
clean up naming conflict styles
LrxGaelle Sep 24, 2026
80b7674
fix preserve rule draft when creating a template
LrxGaelle Oct 9, 2026
733fb19
fix show leave confirmation only for unsaved changes
LrxGaelle Oct 9, 2026
13697b6
fix draft initialization and unsaved changes tracking & add onboardin…
LrxGaelle Oct 9, 2026
c4b307a
fix support template navigation in folder rule manager
LrxGaelle Oct 12, 2026
daa0da0
open naming conflict modal from file name cell
LrxGaelle Oct 12, 2026
d8212c3
fix truncate n_chars default value to max length
LrxGaelle Oct 12, 2026
70a631b
inform users about inherited recursive rules & add counter on create …
LrxGaelle Oct 12, 2026
a171393
use new API for lists, block used list deletion, simplify constraint …
Amoki Oct 19, 2026
e433074
fix enforce strict rule validation in conflict modal
LrxGaelle Oct 20, 2026
dd420dc
allow editing part names
LrxGaelle Oct 21, 2026
7800c26
add modal for lists in use
LrxGaelle Oct 21, 2026
8ee4edb
fix add naming conflict modal to FileTypeCell and filter conflicting …
LrxGaelle Oct 22, 2026
6336329
fix add default placeholder for rule part names
LrxGaelle Oct 23, 2026
7687ff7
preserve default part names when override is empty & fix prevent fals…
LrxGaelle Oct 23, 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
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@bimdata/bcf-components": "6.7.8",
"@bimdata/components": "1.10.3",
"@bimdata/design-system": "2.4.4",
"@bimdata/typescript-fetch-api-client": "10.48.0",
"@bimdata/typescript-fetch-api-client": "10.48.1",
"@bimdata/viewer": "2.20.2-beta.2",
"@paddle/paddle-js": "^1.6.5",
"async": "^3.2.6",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@
@download="$emit('download', file)"
@file-clicked="$emit('file-clicked', file)"
@manage-access="$emit('manage-access', file)"
@manage-naming-rule="$emit('manage-naming-rule', file)"
@open-tag-manager="$emit('open-tag-manager', file)"
@open-versioning-manager="$emit('open-versioning-manager', file)"
@open-visa-manager="$emit('open-visa-manager', file)"
Expand Down Expand Up @@ -288,6 +289,7 @@ export default {
"file-clicked",
"go-folders-view",
"manage-access",
"manage-naming-rule",
"open-tag-manager",
"open-versioning-manager",
"open-visa-manager",
Expand Down
143 changes: 132 additions & 11 deletions src/components/specific/files/files-manager/FilesManager.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
:spaceSubInfo="spaceSubInfo"
:importFromOtherProjectsActions="importFromOtherProjectsActions"
:initialSearchText="searchText"
:refreshFiles="refreshFiles"
@update:searchText="searchText = $event"
@upload-files="uploadFiles"
@manage-naming-conflicts="openNamingConflictsModal"
/>
<div class="files-manager__content">
<transition name="slide-fade-left">
Expand Down Expand Up @@ -74,8 +76,9 @@
:loadingFileIds="loadingFileIds"
:selection="selection"
:filesToUpload="filesToUpload"
:folder="currentFolder"
:folder="folderWithNamingPreview"
:foldersToUpload="foldersToUpload"
:hasNamingConflict="hasNamingConflict"
@back-parent-folder="backToParent"
@create-model="createModelFromFile"
@create-photosphere="createModelFromFile($event, MODEL_TYPE.PHOTOSPHERE)"
Expand All @@ -88,6 +91,7 @@
@file-clicked="onFileSelected"
@file-uploaded="$emit('file-uploaded')"
@manage-access="openAccessManager"
@manage-naming-rule="openFolderNamingConstraintManager"
@open-tag-manager="openTagManager"
@open-versioning-manager="openVersioningManager"
@open-visa-manager="openVisaManager"
Expand All @@ -111,6 +115,7 @@
@file-clicked="onFileSelected"
@go-folders-view="goFoldersView"
@manage-access="openAccessManager"
@manage-naming-rule="openFolderNamingConstraintManager"
@open-tag-manager="openTagManager"
@open-versioning-manager="openVersioningManager"
@open-visa-manager="openVisaManager"
Expand Down Expand Up @@ -205,12 +210,14 @@ import FileService from "../../../../services/FileService.js";
import TagService from "../../../../services/TagService";
import { useFiles } from "../../../../state/files.js";
import { useModels } from "../../../../state/models.js";
import { useNamingConstraints } from "../../../../state/naming-constraints.js";
import { useProjects } from "../../../../state/projects.js";
import { useSpaces } from "../../../../state/spaces.js";
import { useVisa } from "../../../../state/visa.js";
import { collectDescendants } from "../../../../utils/file-tree.js";
import { isFolder } from "../../../../utils/file-structure.js";
import { getFilesFromEvent } from "../../../../utils/files.js";
import { matchName } from "../../../../utils/naming-constraint.js";
import { isFullTotal } from "../../../../utils/spaces.js";
import { fileUploadInput } from "../../../../utils/upload.js";

Expand All @@ -225,6 +232,8 @@ import FilesManagerOnboarding from "./files-manager-onboarding/FilesManagerOnboa
import FileTree from "../file-tree/FileTree.vue";
import FileTreePreviewModal from "../file-tree-preview-modal/FileTreePreviewModal.vue";
import FolderAccessManager from "../folder-access-manager/FolderAccessManager.vue";
import FolderNamingConstraintManager from "../naming-constraint/FolderNamingConstraintManager.vue";
import NamingConflictModal from "../naming-constraint/NamingConflictModal.vue";
import FoldersTable from "../folder-table/FoldersTable.vue";
import SubscriptionModal from "../../subscriptions/subscription-modal/SubscriptionModal.vue";
import TagsMain from "../../tags/tags-main/TagsMain.vue";
Expand Down Expand Up @@ -264,6 +273,10 @@ export default {
type: Object,
required: true,
},
refreshFiles: {
type: Function,
required: true,
},
},
emits: ["file-uploaded", "file-updated", "model-created"],
setup(props, { emit }) {
Expand All @@ -280,8 +293,14 @@ export default {
const { createModel, createPhotosphere, deleteModels } = useModels();

const { fetchToValidateVisas, fetchCreatedVisas } = useVisa();

const { getEffectiveFolderRule } = useNamingConstraints();
const currentFolder = ref(null);
const currentFolderNamingRule = ref(null);
const folderWithNamingPreview = computed(() =>
currentFolder.value
? { ...currentFolder.value, namingConstraintPreview: currentFolderNamingRule.value }
: currentFolder.value,
);
const currentFiles = ref([]);
const toValidateVisas = ref([]);
const createdVisas = ref([]);
Expand Down Expand Up @@ -337,20 +356,53 @@ export default {

const filesToUpload = ref([]);
const foldersToUpload = ref([]);
const uploadFiles = async (event, folder = currentFolder.value) => {
const { files, folders } = await getFilesFromEvent(event);
const proceedUpload = async ({ files, folders }, folder) => {
files.forEach((file) => (file.folder = folder));

filesToUpload.value = files;
foldersToUpload.value = await Promise.all(
folders.map((f) => FileService.createFolderStructure(props.project, folder, f)),
);

setTimeout(() => {
filesToUpload.value = [];
foldersToUpload.value = [];
}, 10);
};
let folders = [];
const uploadFiles = async (event, folder = currentFolder.value) => {
const { files, folders } = await getFilesFromEvent(event);

const rule = await getEffectiveFolderRule(props.project, folder);
const invalidFiles = rule ? files.filter((file) => !matchName(file.name, rule)) : [];

if (invalidFiles.length > 0) {
openModal({
component: NamingConflictModal,
props: {
project: props.project,
documents: invalidFiles.map((file, i) => ({ id: `upload-${i}`, name: file.name })),
rule,
persistChanges: false,
onClose: closeModal,
onConfirm: ({ renamed, deleted }) => {
const deletedIds = new Set(deleted.map((d) => d.id));
const renamedById = new Map(renamed.map((r) => [r.id, r.name]));
const finalFiles = invalidFiles
.map((file, i) => ({ file, id: `upload-${i}` }))
.filter(({ id }) => !deletedIds.has(id))
.map(({ file, id }) => {
const name = renamedById.get(id);
return name ? new File([file], name, { type: file.type }) : file;
});
const validFiles = files.filter((file) => matchName(file.name, rule));
proceedUpload({ files: [...validFiles, ...finalFiles], folders }, folder);
},
},
});
return;
}

proceedUpload({ files, folders }, folder);
};

const loadingFileIds = ref([]);
const isCreatingModels = ref(false);
Expand Down Expand Up @@ -544,6 +596,50 @@ export default {
}, 100);
};

const openFolderNamingConstraintManager = (folder) => {
openSidePanel("right", {
component: FolderNamingConstraintManager,
props: {
project: props.project,
folder,
refreshFiles: props.refreshFiles,
},
});
};

const openNamingConflictsModal = async () => {
const conflicting = allFiles.value.filter((file) => file.naming_constraint_conflict);
if (conflicting.length === 0) {
pushNotification({
type: "success",
title: t("NamingConstraint.noConflictsTitle"),
message: t("NamingConstraint.noConflictsMessage"),
});
return;
}
const documents = await Promise.all(
conflicting.map(async (file) => {
const folder = allFolders.value.find((f) => f.id === file.parent_id);
const effective = folder ? await getEffectiveFolderRule(props.project, folder) : null;
return { ...file, namingRule: effective };
}),
);
openModal({
component: NamingConflictModal,
props: {
project: props.project,
documents,
allFolders: allFolders.value,
rule: null,
showRulesByGroup: true,
onClose: closeModal,
onConfirm: async () => {
await props.refreshFiles();
},
},
});
};

const visasLoading = ref(false);
const openVisaManager = (file) => {
onTabChange(filesTabs[2]);
Expand Down Expand Up @@ -683,6 +779,19 @@ export default {
const allFiles = computed(() => getFilesInFolder(props.fileStructure));
const allFolders = computed(() => getFoldersInFolder(props.fileStructure));

const hasNamingConflict = (folder) => {
if (!folder?.children?.length) {
return false;
}

return folder.children.some((child) => {
if (isFolder(child)) {
return hasNamingConflict(child);
}
return child.naming_constraint_conflict;
});
};

const filesTabs = [
{
id: "folders",
Expand Down Expand Up @@ -758,11 +867,15 @@ export default {
watch(
() => props.fileStructure,
(struct) => {
const folderId = gedTargetFolder.get();
const currentFolderId = currentFolder.value?.id;

if (currentFolderId) {
const folder = handler.get({
nature: FILE_TYPE.FOLDER,
id: currentFolderId,
});

if (folderId) {
jumpToTargetFolder(folderId);
gedTargetFolder.clear();
currentFolder.value = folder ? handler.deserialize(folder) : struct;
} else {
currentFolder.value = struct;
}
Expand All @@ -772,11 +885,15 @@ export default {

watch(
() => currentFolder.value,
(folder) => {
async (folder) => {
if (!folder) return;

const childrenFolders = folder.children.filter(isFolder).sort(sortByName);
const childrenFiles = folder.children.filter((c) => !isFolder(c)).sort(sortByName);

currentFiles.value = childrenFolders.concat(childrenFiles);
gedTargetFolder.set(folder.id);
currentFolderNamingRule.value = await getEffectiveFolderRule(props.project, folder);
},
{ immediate: true },
);
Expand All @@ -788,6 +905,7 @@ export default {
allTags,
allVisas,
currentFolder,
folderWithNamingPreview,
currentSpace,
currentVisa,
displayedFiles,
Expand Down Expand Up @@ -829,10 +947,13 @@ export default {
fileUploadInput,
goFoldersView,
goVisasView,
hasNamingConflict,
isFullTotal,
moveFiles,
onFileSelected,
openAccessManager,
openFolderNamingConstraintManager,
openNamingConflictsModal,
openFileDeleteModal,
openVisaDeleteModal,
openSidePanel,
Expand Down
Loading