feat: Adds the ability to publish an article (#5365)

* feat: Adds the ability to publish an article

* chore: Disabled publish button and dropdown when there is no article id

* chore: Review fixes

* chore: Review fixes

* Update app/javascript/dashboard/routes/dashboard/helpcenter/components/Header/EditArticleHeader.vue

* chore: Review fixes

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
Sivin Varghese 2022-09-02 12:53:18 +05:30 committed by GitHub
parent b16c5de7ca
commit 03c8251cc3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 131 additions and 9 deletions

View file

@ -12,6 +12,11 @@ export default {
SNOOZED: 'snoozed', SNOOZED: 'snoozed',
ALL: 'all', ALL: 'all',
}, },
ARTICLE_STATUS_TYPES: {
DRAFT: 0,
PUBLISH: 1,
ARCHIVE: 2,
},
LAYOUT_TYPES: { LAYOUT_TYPES: {
CONDENSED: 'condensed', CONDENSED: 'condensed',
EXPANDED: 'expanded', EXPANDED: 'expanded',

View file

@ -20,6 +20,7 @@
"EDIT_HEADER": { "EDIT_HEADER": {
"ALL_ARTICLES": "All Articles", "ALL_ARTICLES": "All Articles",
"PUBLISH_BUTTON": "Publish", "PUBLISH_BUTTON": "Publish",
"MOVE_TO_ARCHIVE_BUTTON": "Move to archived",
"PREVIEW": "Preview", "PREVIEW": "Preview",
"ADD_TRANSLATION": "Add translation", "ADD_TRANSLATION": "Add translation",
"OPEN_SIDEBAR": "Open sidebar", "OPEN_SIDEBAR": "Open sidebar",
@ -143,7 +144,8 @@
} }
}, },
"ADD": { "ADD": {
"CREATE_FLOW": [{ "CREATE_FLOW": [
{
"title": "Help center information", "title": "Help center information",
"route": "new_portal_information", "route": "new_portal_information",
"body": "Basic information about portal", "body": "Basic information about portal",
@ -286,6 +288,12 @@
"ERROR": "Error while saving article" "ERROR": "Error while saving article"
} }
}, },
"PUBLISH_ARTICLE": {
"API": {
"ERROR": "Error while publishing article",
"SUCCESS": "Article publishied successfully"
}
},
"ARCHIVE_ARTICLE": { "ARCHIVE_ARTICLE": {
"API": { "API": {
"ERROR": "Error while archiving article", "ERROR": "Error while archiving article",

View file

@ -59,19 +59,58 @@
color-scheme="secondary" color-scheme="secondary"
@click="closeSidebar" @click="closeSidebar"
/> />
<woot-button <div class="article--buttons">
class-names="article--buttons" <div class="button-group">
size="small" <woot-button
color-scheme="primary" class-names="publish-button"
> size="small"
{{ $t('HELP_CENTER.EDIT_HEADER.PUBLISH_BUTTON') }} color-scheme="primary"
</woot-button> :is-disabled="!articleSlug || isPublishedArticle"
@click="updateArticleStatus(ARTICLE_STATUS_TYPES.PUBLISH)"
>
{{ $t('HELP_CENTER.EDIT_HEADER.PUBLISH_BUTTON') }}
</woot-button>
<woot-button
ref="arrowDownButton"
size="small"
icon="chevron-down"
:is-disabled="!articleSlug || isArchivedArticle"
@click="openActionsDropdown"
/>
</div>
<div
v-if="showActionsDropdown"
v-on-clickaway="closeActionsDropdown"
class="dropdown-pane dropdown-pane--open"
>
<woot-dropdown-menu>
<woot-dropdown-item>
<woot-button
variant="clear"
color-scheme="secondary"
size="small"
icon="book-clock"
@click="updateArticleStatus(ARTICLE_STATUS_TYPES.ARCHIVE)"
>
{{ $t('HELP_CENTER.EDIT_HEADER.MOVE_TO_ARCHIVE_BUTTON') }}
</woot-button>
</woot-dropdown-item>
</woot-dropdown-menu>
</div>
</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import alertMixin from 'shared/mixins/alertMixin';
import { mixin as clickaway } from 'vue-clickaway';
import wootConstants from 'dashboard/constants.js';
const { ARTICLE_STATUS_TYPES } = wootConstants;
export default { export default {
mixins: [alertMixin, clickaway],
props: { props: {
backButtonLabel: { backButtonLabel: {
type: String, type: String,
@ -97,6 +136,9 @@ export default {
data() { data() {
return { return {
isSidebarOpen: false, isSidebarOpen: false,
showActionsDropdown: false,
alertMessage: '',
ARTICLE_STATUS_TYPES: ARTICLE_STATUS_TYPES,
}; };
}, },
computed: { computed: {
@ -105,6 +147,21 @@ export default {
? this.$t('HELP_CENTER.EDIT_HEADER.SAVING') ? this.$t('HELP_CENTER.EDIT_HEADER.SAVING')
: this.$t('HELP_CENTER.EDIT_HEADER.SAVED'); : this.$t('HELP_CENTER.EDIT_HEADER.SAVED');
}, },
articleSlug() {
return this.$route.params.articleSlug;
},
currentPortalSlug() {
return this.$route.params.portalSlug;
},
currentArticleStatus() {
return this.$store.getters['articles/articleStatus'](this.articleSlug);
},
isPublishedArticle() {
return this.currentArticleStatus === 'published';
},
isArchivedArticle() {
return this.currentArticleStatus === 'archived';
},
}, },
methods: { methods: {
onClickGoBack() { onClickGoBack() {
@ -116,6 +173,36 @@ export default {
onClickAdd() { onClickAdd() {
this.$emit('add'); this.$emit('add');
}, },
async updateArticleStatus(status) {
try {
await this.$store.dispatch('articles/update', {
portalSlug: this.currentPortalSlug,
articleId: this.articleSlug,
status: status,
});
this.statusUpdateSuccessMessage(status);
this.closeActionsDropdown();
} catch (error) {
this.alertMessage =
error?.message || this.statusUpdateErrorMessage(status);
} finally {
this.showAlert(this.alertMessage);
}
},
statusUpdateSuccessMessage(status) {
if (status === this.ARTICLE_STATUS_TYPES.PUBLISH) {
this.alertMessage = this.$t('HELP_CENTER.PUBLISH_ARTICLE.API.SUCCESS');
} else if (status === this.ARTICLE_STATUS_TYPES.ARCHIVE) {
this.alertMessage = this.$t('HELP_CENTER.ARCHIVE_ARTICLE.API.SUCCESS');
}
},
statusUpdateErrorMessage(status) {
if (status === this.ARTICLE_STATUS_TYPES.PUBLISH) {
this.alertMessage = this.$t('HELP_CENTER.PUBLISH_ARTICLE.API.ERROR');
} else if (status === this.ARTICLE_STATUS_TYPES.ARCHIVE) {
this.alertMessage = this.$t('HELP_CENTER.ARCHIVE_ARTICLE.API.ERROR');
}
},
openSidebar() { openSidebar() {
this.isSidebarOpen = true; this.isSidebarOpen = true;
this.$emit('open'); this.$emit('open');
@ -124,6 +211,12 @@ export default {
this.isSidebarOpen = false; this.isSidebarOpen = false;
this.$emit('close'); this.$emit('close');
}, },
openActionsDropdown() {
this.showActionsDropdown = !this.showActionsDropdown;
},
closeActionsDropdown() {
this.showActionsDropdown = false;
},
}, },
}; };
</script> </script>
@ -149,6 +242,9 @@ export default {
} }
.article--buttons { .article--buttons {
margin-left: var(--space-smaller); margin-left: var(--space-smaller);
.dropdown-pane {
right: var(--space-smaller);
}
} }
.draft-status { .draft-status {
margin-right: var(--space-smaller); margin-right: var(--space-smaller);

View file

@ -49,6 +49,9 @@ import ArticleSettings from './ArticleSettings.vue';
import Spinner from 'shared/components/Spinner'; import Spinner from 'shared/components/Spinner';
import portalMixin from '../../mixins/portalMixin'; import portalMixin from '../../mixins/portalMixin';
import alertMixin from 'shared/mixins/alertMixin'; import alertMixin from 'shared/mixins/alertMixin';
import wootConstants from 'dashboard/constants';
const { ARTICLE_STATUS_TYPES } = wootConstants;
export default { export default {
components: { components: {
EditArticleHeader, EditArticleHeader,
@ -152,7 +155,7 @@ export default {
await this.$store.dispatch('articles/update', { await this.$store.dispatch('articles/update', {
portalSlug: this.selectedPortalSlug, portalSlug: this.selectedPortalSlug,
articleId: this.articleId, articleId: this.articleId,
status: 2, status: ARTICLE_STATUS_TYPES.ARCHIVE,
}); });
this.alertMessage = this.$t('HELP_CENTER.ARCHIVE_ARTICLE.API.SUCCESS'); this.alertMessage = this.$t('HELP_CENTER.ARCHIVE_ARTICLE.API.SUCCESS');
} catch (error) { } catch (error) {

View file

@ -20,6 +20,12 @@ export const getters = {
.filter(article => article !== undefined); .filter(article => article !== undefined);
return articles; return articles;
}, },
articleStatus: (...getterArguments) => articleId => {
const [state] = getterArguments;
const article = state.articles.byId[articleId];
if (!article) return undefined;
return article.status;
},
getMeta: state => { getMeta: state => {
return state.meta; return state.meta;
}, },

View file

@ -34,6 +34,10 @@ describe('#getters', () => {
}); });
}); });
it('articleStatus', () => {
expect(getters.articleStatus(state)(1)).toEqual('draft');
});
it('isFetchingArticles', () => { it('isFetchingArticles', () => {
expect(getters.isFetching(state)).toEqual(true); expect(getters.isFetching(state)).toEqual(true);
}); });