<commit_before><!--
    This template is used to show the comments by framework
    This is controlled by an event sent from the EditorToolbar.vue template
    which triggers Framework.vue to open this component.
-->
<template>
    <aside
        id="right-side-bar__comments"
        class="menu has-background-lightest">
        <div class="right-aside-bar__title">
            <h3 class="title is-size-3">
                Comments
            </h3>
        </div>
        <!-- for each comment in time sequence
            click to scroll to position in framework eventually -->
        <!-- for each response -->
        <div
            v-if="isCommentsBusy"
            class="has-text-centered">
            <span class="icon is-large has-text-center has-text-link">
                <i class="fas fa-3x fa-spinner is-info fa-pulse" />
            </span>
        </div>
        <div v-if="!isCommentsBusy">
            <div
                v-if="commentWrapperList.length <= 0"
                class="has-text-centered">
                <span class="has-text-center">
                    <p><i class="fa fa-exclamation-circle" /> No comments available</p>
                </span>
            </div>
            <template v-if="commentWrapperList.length > 0">
                <div
                    v-for="(commentWrapper, index) in commentWrapperList"
                    :key="index"
                    class="comment-list">
                    <h4
                        class="comment-list__about"
                        @click="setUpScroll(commentWrapper)">
                        {{ commentWrapper.aboutName }}
                    </h4>
                    <Comment
                        :comment="commentWrapper"
                        :key="commentWrapper.commentId"
                        :canReply="canReplyToComments" />
                    <div class="buttons is-right">
                        <div
                            class="button is-small is-outlined is-primary"
                            title="reply"
                            @click="handleClickReply(commentWrapper)">
                            <span class="icon">
                                <i class="fa fa-reply" />
                            </span>
                            <span>reply</span>
                        </div>
                    </div>
                </div>
            </template>
        </div>
    </aside>
</template>
<script>
import Comment from './Comment.vue';
import common from '@/mixins/common.js';

export default {
    name: 'Comments',
    mixins: [common],
    data() {
        return {
            COMMENT_SEARCH_SIZE: 10000,
            isCommentsBusy: false,
            localFrameworkCommentList: [],
            commentAboutMap: {},
            commentWrapperList: [],
            commentWrapperMap: {},
            canReplyToComments: false
        };
    },
    components: {
        Comment
    },
    methods: {
        setUpScroll: function(comment) {
            let scrollObj = {ts: Date.now(), scrollId: '#scroll-' + comment.aboutId.split('/').pop()};
            this.$store.commit('editor/setCommentScrollTo', scrollObj);
        },
        handleClickReply: function(comment) {
            this.$store.commit('editor/setAddCommentAboutId', comment.aboutId);
            this.$store.commit('editor/setAddCommentType', 'reply');
            this.$store.commit('editor/setCommentToReply', comment.comment);
            this.$store.commit('app/showModal', {component: 'AddComment'});
        },
        determineCanModifyComment: function(comment) {
            if (this.loggedOnPerson.shortId().equals(comment.creator)) return true;
            else return false;
        },
        buildCommentWrapper: function(comment, aboutName, isTopLevel) {
            let commentWrapper = {};
            let commentCreatorPerson = this.frameworkCommentPersonMap[comment.creator];
            commentWrapper.comment = comment;
            commentWrapper.creator = commentCreatorPerson;
            commentWrapper.aboutId = comment.about;
            commentWrapper.aboutName = aboutName;
            commentWrapper.commentId = comment.shortId();
            commentWrapper.creatorName = commentCreatorPerson.name;
            commentWrapper.creatorEmail = commentCreatorPerson.email;
            commentWrapper.dateCreated = comment.dateCreated - 0;
            if (comment.lastEditDate) commentWrapper.lastEditDate = comment.lastEditDate - 0;
            commentWrapper.commentText = comment.text;
            commentWrapper.isTopLevel = isTopLevel;
            commentWrapper.canModify = this.determineCanModifyComment(comment);
            commentWrapper.replies = [];
            return commentWrapper;
        },
        buildFrameworkCommentWrappers: function() {
            let fwkComments = this.commentAboutMap[this.currentFramework.shortId()];
            if (fwkComments && fwkComments.length > 0) {
                for (let fc of fwkComments) {
                    let cw = this.buildCommentWrapper(fc, this.currentFramework.getName(), true);
                    this.commentWrapperList.push(cw);
                    this.commentWrapperMap[fc.shortId()] = cw;
                }
            }
        },
        getCompetencyName(compId) {
            let comp = EcRepository.getBlocking(compId);
            if (comp) return comp.getName();
            else return 'Unknown Competency';
        },
        buildCompetencyCommentWrappers: function() {
            if (this.currentFramework.competency) {
                for (let fwkCompId of this.currentFramework.competency) {
                    let compComments = this.commentAboutMap[fwkCompId];
                    if (compComments && compComments.length > 0) {
                        let compName = this.getCompetencyName(fwkCompId);
                        for (let cc of compComments) {
                            let cw = this.buildCommentWrapper(cc, compName, true);
                            this.commentWrapperList.push(cw);
                            this.commentWrapperMap[cc.shortId()] = cw;
                        }
                    }
                }
            }
        },
        addRepliesToParentWrapper: function(replyList) {
            for (let replyId of replyList) {
                let reply = this.commentWrapperMap[replyId];
                let replyAboutId = reply.aboutId;
                let parent = this.commentWrapperMap[replyAboutId];
                parent.replies.push(reply);
            }
        },
        buildReplyCommentWrappers: function() {
            let replyList = [];
            for (let c of this.frameworkCommentList) {<commit_msg>Make sure parent comment is still valid before adding replies CA-557<commit_after><!--
    This template is used to show the comments by framework
    This is controlled by an event sent from the EditorToolbar.vue template
    which triggers Framework.vue to open this component.
-->
<template>
    <aside
        id="right-side-bar__comments"
        class="menu has-background-lightest">
        <div class="right-aside-bar__title">
            <h3 class="title is-size-3">
                Comments
            </h3>
        </div>
        <!-- for each comment in time sequence
            click to scroll to position in framework eventually -->
        <!-- for each response -->
        <div
            v-if="isCommentsBusy"
            class="has-text-centered">
            <span class="icon is-large has-text-center has-text-link">
                <i class="fas fa-3x fa-spinner is-info fa-pulse" />
            </span>
        </div>
        <div v-if="!isCommentsBusy">
            <div
                v-if="commentWrapperList.length <= 0"
                class="has-text-centered">
                <span class="has-text-center">
                    <p><i class="fa fa-exclamation-circle" /> No comments available</p>
                </span>
            </div>
            <template v-if="commentWrapperList.length > 0">
                <div
                    v-for="(commentWrapper, index) in commentWrapperList"
                    :key="index"
                    class="comment-list">
                    <h4
                        class="comment-list__about"
                        @click="setUpScroll(commentWrapper)">
                        {{ commentWrapper.aboutName }}
                    </h4>
                    <Comment
                        :comment="commentWrapper"
                        :key="commentWrapper.commentId"
                        :canReply="canReplyToComments" />
                    <div class="buttons is-right">
                        <div
                            class="button is-small is-outlined is-primary"
                            title="reply"
                            @click="handleClickReply(commentWrapper)">
                            <span class="icon">
                                <i class="fa fa-reply" />
                            </span>
                            <span>reply</span>
                        </div>
                    </div>
                </div>
            </template>
        </div>
    </aside>
</template>
<script>
import Comment from './Comment.vue';
import common from '@/mixins/common.js';

export default {
    name: 'Comments',
    mixins: [common],
    data() {
        return {
            COMMENT_SEARCH_SIZE: 10000,
            isCommentsBusy: false,
            localFrameworkCommentList: [],
            commentAboutMap: {},
            commentWrapperList: [],
            commentWrapperMap: {},
            canReplyToComments: false
        };
    },
    components: {
        Comment
    },
    methods: {
        setUpScroll: function(comment) {
            let scrollObj = {ts: Date.now(), scrollId: '#scroll-' + comment.aboutId.split('/').pop()};
            this.$store.commit('editor/setCommentScrollTo', scrollObj);
        },
        handleClickReply: function(comment) {
            this.$store.commit('editor/setAddCommentAboutId', comment.aboutId);
            this.$store.commit('editor/setAddCommentType', 'reply');
            this.$store.commit('editor/setCommentToReply', comment.comment);
            this.$store.commit('app/showModal', {component: 'AddComment'});
        },
        determineCanModifyComment: function(comment) {
            if (this.loggedOnPerson.shortId().equals(comment.creator)) return true;
            else return false;
        },
        buildCommentWrapper: function(comment, aboutName, isTopLevel) {
            let commentWrapper = {};
            let commentCreatorPerson = this.frameworkCommentPersonMap[comment.creator];
            commentWrapper.comment = comment;
            commentWrapper.creator = commentCreatorPerson;
            commentWrapper.aboutId = comment.about;
            commentWrapper.aboutName = aboutName;
            commentWrapper.commentId = comment.shortId();
            commentWrapper.creatorName = commentCreatorPerson.name;
            commentWrapper.creatorEmail = commentCreatorPerson.email;
            commentWrapper.dateCreated = comment.dateCreated - 0;
            if (comment.lastEditDate) commentWrapper.lastEditDate = comment.lastEditDate - 0;
            commentWrapper.commentText = comment.text;
            commentWrapper.isTopLevel = isTopLevel;
            commentWrapper.canModify = this.determineCanModifyComment(comment);
            commentWrapper.replies = [];
            return commentWrapper;
        },
        buildFrameworkCommentWrappers: function() {
            let fwkComments = this.commentAboutMap[this.currentFramework.shortId()];
            if (fwkComments && fwkComments.length > 0) {
                for (let fc of fwkComments) {
                    let cw = this.buildCommentWrapper(fc, this.currentFramework.getName(), true);
                    this.commentWrapperList.push(cw);
                    this.commentWrapperMap[fc.shortId()] = cw;
                }
            }
        },
        getCompetencyName(compId) {
            let comp = EcRepository.getBlocking(compId);
            if (comp) return comp.getName();
            else return 'Unknown Competency';
        },
        buildCompetencyCommentWrappers: function() {
            if (this.currentFramework.competency) {
                for (let fwkCompId of this.currentFramework.competency) {
                    let compComments = this.commentAboutMap[fwkCompId];
                    if (compComments && compComments.length > 0) {
                        let compName = this.getCompetencyName(fwkCompId);
                        for (let cc of compComments) {
                            let cw = this.buildCommentWrapper(cc, compName, true);
                            this.commentWrapperList.push(cw);
                            this.commentWrapperMap[cc.shortId()] = cw;
                        }
                    }
                }
            }
        },
        addRepliesToParentWrapper: function(replyList) {
            for (let replyId of replyList) {
                let reply = this.commentWrapperMap[replyId];
                let replyAboutId = reply.aboutId;
                let parent = this.commentWrapperMap[replyAboutId];
                if (parent) parent.replies.push(reply);
            }
        },
        buildReplyCommentWrappers: function() {
            let replyList = [];
            for (let c of this.frameworkCommentList) {
{'fraction_non_alphanumeric': 0.10260405074560427, 'fraction_numerical': 0.00274501075747459, 'mean_word_length': 1.5569044006069803, 'pattern_counts': {'":': 0, '<': 89, '<?xml version=': 0, '>': 93, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4876318', 'n_tokens_mistral': 3412, 'n_tokens_neox': 3268, 'n_words': 666}