Reputation: 1
This is the js file in "documents" enterprise base addon I just want to add "documetns_type_id" in here export const inspectorFields = [] through custom addon.
/** @odoo-module **/
import { device } from "web.config";
import { str_to_datetime } from "web.time";
import { session } from "@web/session";
import { KeepLast } from "@web/core/utils/concurrency";
import { intersection } from "@web/core/utils/arrays";
import { AutoComplete } from "@web/core/autocomplete/autocomplete";
import { x2ManyCommands } from "@web/core/orm_service";
import { useBus, useService } from "@web/core/utils/hooks";
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
import { FileUploader } from "@web/views/fields/file_handler";
import { ChatterContainer } from "@mail/components/chatter_container/chatter_container";
import { DocumentsInspectorField } from "./documents_inspector_field";
import { download } from "@web/core/network/download";
import { onNewPdfThumbnail } from "../helper/documents_pdf_thumbnail_service";
import { useTriggerRule } from "@documents/views/hooks";
const { Component, markup, useEffect, useState, useRef, onPatched, onWillUpdateProps, onWillStart } = owl;
async function toggleArchive(model, resModel, resIds, doArchive) {
const method = doArchive ? "action_archive" : "action_unarchive";
const action = await model.orm.call(resModel, method, [resIds]);
if (action && Object.keys(action).length !== 0) {
model.action.doAction(action);
}
}
export const inspectorFields = [
"attachment_id",
"active",
"activity_ids",
"available_rule_ids",
"checksum",
"display_name",
"folder_id",
"thumbnail_status",
"lock_uid",
"message_attachment_count",
"message_follower_ids",
"message_ids",
"mimetype",
"name",
"owner_id",
"partner_id",
"previous_attachment_ids",
"res_id",
"res_model",
"res_model_name",
"res_name",
"tag_ids",
"type",
"url",
"file_size",
];
export class DocumentsInspector extends Component {
setup() {
this.orm = useService("orm");
this.action = useService("action");
this.dialogService = useService("dialog");
this.notificationService = useService("notification");
this.documentsReplaceInput = useRef("replaceFileInput");
this.chatterContainer = useRef("chatterContainer");
this.keepLast = new KeepLast();
this.previewLockCount = 0;
this.str_to_datetime = str_to_datetime;
const { triggerRule } = useTriggerRule();
this._triggerRule = triggerRule;
const { bus: fileUploadBus } = useService("file_upload");
useBus(fileUploadBus, "FILE_UPLOAD_LOADED", (ev) => {
let documentId = ev.detail.upload.data.get("document_id");
if (documentId && this.resIds.includes(Number.parseInt(documentId))) {
this.state.previousAttachmentDirty = true;
}
});
// Avoid generating new urls if they were generated within this component's lifetime
this.generatedUrls = {};
this.state = useState({
previousAttachmentData: null,
previousAttachmentDirty: true,
showChatter: this.isMobile,
});
const updateLockedState = (props) => {
this.isLocked =
(props.selection.find((rec) => rec.data.lock_uid && rec.data.lock_uid[0] !== session.uid) && true) ||
false;
const folderIds = props.selection.map((rec) => rec.data.folder_id[0]);
const folders = this.env.searchModel.getFolders().filter((folder) => folderIds.includes(folder.id));
this.isEditDisabled = !!folders.find((folder) => !folder.has_write_access);
};
onWillStart(() => {
updateLockedState(this.props);
this.updateAttachmentHistory(null);
});
onWillUpdateProps((nextProps) => {
this.generatedUrl = false;
updateLockedState(nextProps);
this.updateAttachmentHistory(nextProps);
});
// Chatter
const chatterCloseHandler = () => {
this.state.showChatter = this.isMobile;
};
const chatterReloadHandler = async () => {
const record = this.props.selection[0];
if (!record) {
return;
}
await record.load();
await record.model.notify();
};
useEffect(
(el) => {
if (!el) {
return;
}
el.addEventListener("o-close-chatter", chatterCloseHandler);
el.addEventListener("reload", chatterReloadHandler);
return () => {
el.removeEventListener("o-close-chatter", chatterCloseHandler);
el.removeEventListener("reload", chatterReloadHandler);
};
},
() => [this.chatterContainer.el && this.chatterContainer.el.querySelector(".o_Chatter")]
);
// Pdf thumbnails
if (this.props.withFilePreview) {
this.pdfService = useService("documents_pdf_thumbnail");
onWillStart(async () => {
this.pdfService.enqueueRecords(this.props.selection);
})
onWillUpdateProps(async (nextProps) => {
this.pdfService.enqueueRecords(nextProps.selection);
})
onNewPdfThumbnail(({ detail }) => {
if (this.props.selection.find(rec => rec.resId === detail.record.resId)) {
this.render(true);
}
});
}
//Mobile specific
if (!this.env.isSmall) {
return;
}
this.inspectorMobileRef = useRef("inspectorMobile");
this.shouldOpenInspector = false;
onWillUpdateProps((nextProps) => {
// Only open the inspector if there is only one selected element and
// it was not previously selected.
this.shouldOpenInspector = nextProps.selection.length === 1;
});
onPatched(() => {
if (!this.inspectorMobileRef.el) {
return;
}
if (this.shouldOpenInspector) {
this.inspectorMobileRef.el.setAttribute("open", "");
}
});
}
get resIds() {
return this.props.selection.map((rec) => rec.resId);
}
get isMobile() {
return this.env.isSmall;
}
updateAttachmentHistory(nextProps) {
const props = nextProps || this.props;
const record = props.selection[0];
if (props.selection.length !== 1) {
this.state.showChatter = this.isMobile;
}
if (!record || props.selection.length !== 1 || !record.data.previous_attachment_ids.count) {
this.keepLast.add(Promise.resolve());
this.state.previousAttachmentData = null;
return;
}
const previousRecord = this.props.selection.length === 1 && this.props.selection[0];
if (
nextProps &&
previousRecord &&
previousRecord.resId === record.resId &&
!this.state.previousAttachmentDirty
) {
return;
}
this.keepLast.add(
this.orm
.searchRead(
"ir.attachment",
[["id", "in", record.data.previous_attachment_ids.records.map((rec) => rec.resId)]],
["name", "create_date", "create_uid"],
{
order: "create_date desc",
}
)
.then((result) => {
this.state.previousAttachmentData = result;
this.state.previousAttachmentDirty = false;
})
);
}
getCurrentFolder() {
return this.env.searchModel.getSelectedFolder();
}
getFolderDescription() {
return markup(this.getCurrentFolder().description);
}
/**
* Returns an object with additional data for our record
*/
getRecordAdditionalData(record) {
const additionalData = {
isGif: new RegExp("image.*(gif)").test(record.data.mimetype),
isImage: new RegExp("image.*(jpeg|jpg|png)").test(record.data.mimetype),
isYoutubeVideo: false,
youtubeToken: undefined,
};
if (record.data.url && record.data.url.length) {
const youtubeUrlMatch = record.data.url.match(
"youtu(?:.be|be.com)/(?:.*v(?:/|=)|(?:.*/)?)([a-zA-Z0-9-_]{11})"
);
if (youtubeUrlMatch && youtubeUrlMatch.length > 1) {
additionalData.isYoutubeVideo = true;
additionalData.youtubeToken = youtubeUrlMatch[1];
}
}
return additionalData;
}
/**
* Returns the classes to give to the file preview
*/
getPreviewClasses(record, additionalData) {
const nbPreviews = this.props.selection.length;
const classes = ["o_document_preview"];
if (record.data.type === "empty") {
classes.push("o_document_request_preview");
}
if (nbPreviews === 1) {
classes.push("o_documents_single_preview");
}
if (additionalData.isImage || additionalData.isYoutubeVideo || (record.isPdf() && record.hasThumbnail())) {
classes.push("o_documents_preview_image");
} else {
classes.push("o_documents_preview_mimetype");
}
if (additionalData.isYoutubeVideo || additionalData.isGif) {
classes.push("o_non_image_preview");
}
return classes.join(" ");
}
isPdfOnly() {
return this.props.selection.every((record) => record.isPdf());
}
download(records) {
if (records.length === 1) {
download({
data: {},
url: `/documents/content/${records[0].resId}`,
});
} else {
download({
data: {
file_ids: records.map(rec => rec.resId),
zip_name: `documents-${moment().format("YYYY-MM-DD")}.zip`,
},
url: "/document/zip",
});
}
}
onDownload() {
if (!this.props.selection.length) {
return;
}
this.download(this.props.selection);
}
// Override during tests.
_writeInClipboard(text) {
navigator.clipboard.writeText(text);
}
async onShare() {
const resIds = this.resIds;
if (!this.generatedUrls[resIds]) {
this.generatedUrls[resIds] = await this.orm.call(
"documents.share",
"action_get_share_url",
[{
document_ids: [x2ManyCommands.replaceWith(this.resIds)],
folder_id: this.env.searchModel.getSelectedFolderId(),
type: "ids",
}],
);
}
this._writeInClipboard(this.generatedUrls[resIds]);
this.notificationService.add(
this.env._t("The share url has been copied to your clipboard."),
{
type: "success",
},
);
}
async onReplace(ev) {
if (!ev.target.files.length) {
return;
}
const record = this.props.selection[0];
await this.env.documentsView.bus.trigger("documents-upload-files", {
files: ev.target.files,
folderId: this.env.searchModel.getSelectedFolderId() || (record.data.folder_id && record.data.folder_id[0]),
recordId: this.props.selection[0].resId,
tagIds: this.env.searchModel.getSelectedTagIds(),
});
ev.target.value = "";
}
async onLock() {
await this.doLockAction(async () => {
const record = this.props.selection[0];
await this.orm.call("documents.document", "toggle_lock", this.resIds);
await record.load();
await record.model.notify();
});
}
async _toggleArchive(state) {
const record = this.props.selection[0];
await toggleArchive(record.model, record.resModel, this.resIds, state);
await record.model.load();
await record.model.notify();
}
async onArchive() {
await this._toggleArchive(true);
}
async onUnarchive() {
await this._toggleArchive(false);
}
async onDelete() {
await this.props.selection[0].model.root.deleteRecords(this.props.selection);
}
getFieldProps(fieldName, additionalProps) {
const props = {
record: this.props.selection[0],
name: fieldName,
selection: this.props.selection,
inspectorReadonly: this.isLocked || this.isEditDisabled,
lockAction: this.doLockAction.bind(this),
};
if (additionalProps) {
Object.assign(props, additionalProps);
}
return props;
}
_getCommonM2M(field) {
const selection = this.props.selection;
let commonData = selection[0].data[field].records.map((rec) => rec.resId);
for (let idx = 1; idx < selection.length; idx++) {
if (commonData.length === 0) {
break;
}
commonData = intersection(
commonData,
selection[idx].data[field].records.map((rec) => rec.resId)
);
}
return commonData.map((id) => selection[0].data[field].records.find((data) => data.resId === id));
}
getCommonTags() {
const searchModelTags = this.env.searchModel.getTags().reduce((res, tag) => {
res[tag.id] = tag;
return res;
}, {});
return this._getCommonM2M("tag_ids")
.filter((rec) => searchModelTags[rec.resId])
.map((rec) => {
const tag = searchModelTags[rec.resId];
return {
id: rec.resId,
name: tag.display_name,
group_name: tag.group_name,
};
});
}
getCommonRules() {
let commonRules = this._getCommonM2M("available_rule_ids");
if (this.props.selection.length > 1) {
commonRules = commonRules.filter((rule) => !rule.data.limited_to_single_record);
}
return commonRules;
}
getAdditionalTags(commonTags) {
return this.env.searchModel.getTags().filter((tag) => {
return !commonTags.find((cTag) => cTag.id === tag.id);
});
}
async removeTag(tag) {
const record = this.props.selection[0];
record.model.root._multiSave(record, {
tag_ids: [x2ManyCommands.forget(tag.id)],
});
}
async addTag(tag, { input }) {
const record = this.props.selection[0];
record.model.root._multiSave(record, {
tag_ids: [x2ManyCommands.linkTo(tag.value)],
});
input.focus();
}
getTagAutocompleteProps(additionalTags) {
return {
value: "",
onSelect: this.addTag.bind(this),
sources: [
{
options: (request) => {
request = request.toLowerCase();
return additionalTags
.filter((tag) =>
(tag.group_name + " > " + tag.display_name).toLowerCase().includes(request)
)
.map((tag) => {
return {
id: tag.id,
value: tag.id,
label: tag.group_name + " > " + tag.display_name,
};
});
},
},
],
placeholder: this.env._t(" + Add a tag"),
};
}
async onClickResModel() {
const record = this.props.selection[0];
const action = await this.orm.call(record.data.res_model, "get_formview_action", [[record.data.res_id]], {
context: record.model.user.context,
});
await this.action.doAction(action);
}
async triggerRule(rule) {
await this._triggerRule(
this.props.selection.map(rec => rec.resId),
rule.resId,
);
}
async onDeletePreviousAttachment(attachmentId) {
if (this.deleting) {
return;
}
await this.doLockAction(async () => {
this.deleting = true;
await this.orm.unlink("ir.attachment", [attachmentId]);
const record = this.props.selection[0];
const model = this.props.selection[0].model;
await record.load();
this.state.previousAttachmentDirty = true;
await model.notify();
this.deleting = false;
});
}
async onDownloadPreviousAttachment(attachmentId) {
window.location = `/web/content/${attachmentId}?download=true`;
}
async onRestorePreviousAttachment(attachmentId) {
const record = this.props.selection[0];
await this.doLockAction(async () => {
await this.orm.write("documents.document", [record.resId], {
attachment_id: attachmentId,
});
await record.load();
this.state.previousAttachmentDirty = true;
await record.model.notify();
});
}
openPreview(mainDocument = false, isPdfSplit = false) {
if ((isPdfSplit && !this.isPdfOnly()) || this.previewLockCount) {
return;
}
const documents = this.props.selection.filter(rec => rec.isViewable());
this.env.documentsView.bus.trigger("documents-open-preview", {
documents: documents,
mainDocument: mainDocument || documents[0],
isPdfSplit,
rules: this.getCommonRules(),
hasPdfSplit: !this.isLocked && !this.isEditDisabled,
});
}
async onEditModel() {
const record = this.props.selection[0];
let defaultResourceRef = false;
if (record.data.res_model && record.data.res_id) {
defaultResourceRef = `${record.data.res_model},${record.data.res_id}`;
}
const models = await this.orm.searchRead("ir.model", [["model", "=", record.data.res_model]], ["id"], {
limit: 1,
});
this.action.doAction(
{
name: this.env._t("Edit the linked record"),
type: "ir.actions.act_window",
res_model: "documents.link_to_record_wizard",
views: [[false, "form"]],
target: "new",
context: {
default_document_ids: [record.resId],
default_resource_ref: defaultResourceRef,
default_is_readonly_model: true,
default_model_id: models[0].id,
},
},
{
onClose: async () => {
await record.model.load();
record.model.notify();
},
}
);
}
onDeleteModel() {
const recordId = this.props.selection[0].resId;
const model = this.props.selection[0].model;
this.dialogService.add(ConfirmationDialog, {
body: this.env._t("Do you really want to unlink this record?"),
confirm: async () => {
await this.orm.call("documents.workflow.rule", "unlink_record", [[recordId]]);
await model.load();
model.notify();
},
});
}
async doLockAction(func) {
this.previewLockCount++;
await func();
this.previewLockCount--;
}
}
DocumentsInspector.components = {
AutoComplete,
ChatterContainer,
DocumentsInspectorField,
FileUploader,
};
if (device.isMobile) {
DocumentsInspector.template = "documents.DocumentsInspectorMobile";
} else {
DocumentsInspector.template = "documents.DocumentsInspector";
}
I have created a view "assets.xml" in my custom addons ateam_adaptations/views/assets.xml
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets_backend" name="documents assets backend" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript"
src="/ateam_adaptations/static/src/views/inspector/documents_inspector.js"/>
</xpath>
</template>
</odoo>
and this is how i am overriding the js file through custom addons ateam_adaptations/static/src/views/inspector/documents_inspector.js:
odoo.define('ateam_adaptations.documents_inspector', function (require) {
"use strict";
console.log("documents_inspector_extension");
var DocumentsInspector = require('@documents/static/src/views/inspector/documents_inspector.js');
console.log("DocumentsInspector", DocumentsInspector);
// Extend the inspectorFields array to include "document_type_id"
DocumentsInspector.inspectorFields.push("document_type_id");
return DocumentsInspector;
});
Upvotes: 0
Views: 559
Reputation: 1
I got the answer of this. In this custom module ateam_adaptations, I add a new js file named documents_inspector.js in this path "ateam_adaptations/static/src/views/inspector/documents_inspector.js" In this js file, I just add the code below:
odoo.define('ateam_adaptations.documents_inspector', async function(require) {
'use strict';
let __exports = {};
const {inspectorFields} = require("@documents/views/inspector/documents_inspector");
inspectorFields.push("document_type_id");
return __exports;
});
and after that, just add the js file in my manifest.py file:
'assets': {
'web.assets_backend': [
'ateam_adaptations/static/src/views/inspector/documents_inspector.js' ] }
and it worked for me.
Upvotes: 0
Reputation: 59
I am assuming that you are using Odoo v16
in your ateam_adaptations/static/src/views/inspector/documents_inspector.js file just add the code below:
/** @odoo-module **/
import {inspectorFields} from "@documents/views/inspector/documents_inspector";
inspectorFields.push("document_type_id");
and that's it!
for loading your custom JS file the assets.xml file is not used anymore and it has been moved to manifest.py file
simply add it like this
'assets': {
'web.assets_backend': [
'ateam_adaptations/static/src/views/inspector/documents_inspector.js'
]
}
I hope it is helpful
Upvotes: 1