diff --git a/server/meeting.go b/server/meeting.go index 241d51b..5bd5704 100644 --- a/server/meeting.go +++ b/server/meeting.go @@ -20,7 +20,7 @@ var ( type Meeting struct { ChannelID string `json:"channelId"` Schedule []time.Weekday `json:"schedule"` - HashtagFormat string `json:"hashtagFormat"` // Default: {ChannelName}-Jan02 + HashtagFormat string `json:"hashtagFormat"` // Default: {ChannelName}-Jan-2 } // GetMeeting returns a meeting @@ -41,9 +41,10 @@ func (p *Plugin) GetMeeting(channelID string) (*Meeting, error) { if err != nil { return nil, err } + paddedChannelName := strings.ReplaceAll(channel.Name, "-", "_") meeting = &Meeting{ Schedule: []time.Weekday{time.Thursday}, - HashtagFormat: strings.Join([]string{fmt.Sprintf("%.15s", channel.Name), "{{ Jan02 }}"}, "-"), + HashtagFormat: strings.Join([]string{fmt.Sprintf("%.15s", paddedChannelName), "{{ Jan 2 }}"}, "_"), ChannelID: channelID, } } @@ -143,8 +144,10 @@ func (p *Plugin) GenerateHashtag(channelID string, nextWeek bool, weekday int) ( prefix = matchGroups[1] hashtagFormat = strings.TrimSpace(matchGroups[2]) postfix = matchGroups[3] + formattedDate := meetingDate.Format(hashtagFormat) + formattedDate = strings.ReplaceAll(formattedDate, " ", "_") - hashtag = fmt.Sprintf("#%s%v%s", prefix, meetingDate.Format(hashtagFormat), postfix) + hashtag = fmt.Sprintf("#%s%v%s", prefix, formattedDate, postfix) } else { hashtag = fmt.Sprintf("#%s", meeting.HashtagFormat) } diff --git a/server/meeting_test.go b/server/meeting_test.go index 4e24e25..a8b5b72 100644 --- a/server/meeting_test.go +++ b/server/meeting_test.go @@ -55,9 +55,9 @@ func TestPlugin_GenerateHashtag(t *testing.T) { meeting: &Meeting{ ChannelID: "QA", Schedule: []time.Weekday{time.Wednesday}, - HashtagFormat: "{{Jan02}}", + HashtagFormat: "{{Jan 2}}", }}, - want: "#" + assertNextWeekdayDate(time.Wednesday, true).Format("Jan02"), + want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Wednesday, true).Format("Jan 2"), " ", "_"), wantErr: false, }, { @@ -67,9 +67,9 @@ func TestPlugin_GenerateHashtag(t *testing.T) { meeting: &Meeting{ ChannelID: "QA Backend", Schedule: []time.Weekday{time.Monday}, - HashtagFormat: "QA-{{January 02 2006}}", + HashtagFormat: "QA_{{January 02 2006}}", }}, - want: "#QA-" + assertNextWeekdayDate(time.Monday, true).Format("January 02 2006"), + want: "#QA_" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, true).Format("January 02 2006"), " ", "_"), wantErr: false, }, { @@ -81,7 +81,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) { Schedule: []time.Weekday{time.Monday}, HashtagFormat: "{{January 02 2006}}.vue", }}, - want: "#" + assertNextWeekdayDate(time.Monday, false).Format("January 02 2006") + ".vue", + want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006"), " ", "_") + ".vue", wantErr: false, }, { @@ -93,7 +93,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) { Schedule: []time.Weekday{time.Monday}, HashtagFormat: "React {{January 02 2006}} Born", }}, - want: "#React " + assertNextWeekdayDate(time.Monday, false).Format("January 02 2006") + " Born", + want: "#React " + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006"), " ", "_") + " Born", wantErr: false, }, { @@ -105,7 +105,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) { Schedule: []time.Weekday{time.Monday}, HashtagFormat: "January 02 2006 {{January 02 2006}} January 02 2006", }}, - want: "#January 02 2006 " + assertNextWeekdayDate(time.Monday, false).Format("January 02 2006") + " January 02 2006", + want: "#January 02 2006 " + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006"), " ", "_") + " January 02 2006", wantErr: false, }, { @@ -117,7 +117,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) { Schedule: []time.Weekday{time.Monday}, HashtagFormat: "{{ January 02 2006 }}", }}, - want: "#" + assertNextWeekdayDate(time.Monday, false).Format("January 02 2006"), + want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("January 02 2006"), " ", "_"), wantErr: false, }, { @@ -129,7 +129,7 @@ func TestPlugin_GenerateHashtag(t *testing.T) { Schedule: []time.Weekday{time.Monday}, HashtagFormat: "{{ Mon Jan _2 }}", }}, - want: "#" + assertNextWeekdayDate(time.Monday, false).Format("Mon Jan _2"), + want: "#" + strings.ReplaceAll(assertNextWeekdayDate(time.Monday, false).Format("Mon Jan _2"), " ", "_"), wantErr: false, }, } @@ -176,7 +176,7 @@ func TestPlugin_GetMeeting(t *testing.T) { }, want: &Meeting{ Schedule: []time.Weekday{time.Thursday}, - HashtagFormat: "Short-{{ Jan02 }}", + HashtagFormat: "Short_{{ Jan 2 }}", ChannelID: "#short.name.channel", }, wantErr: false, @@ -190,7 +190,7 @@ func TestPlugin_GetMeeting(t *testing.T) { }, want: &Meeting{ Schedule: []time.Weekday{time.Thursday}, - HashtagFormat: "Very Long Chann-{{ Jan02 }}", + HashtagFormat: "Very Long Chann_{{ Jan 2 }}", ChannelID: "#long.name.channel", }, wantErr: false, diff --git a/webapp/src/components/meeting_settings/meeting_settings.jsx b/webapp/src/components/meeting_settings/meeting_settings.jsx index 47ee439..44e3290 100644 --- a/webapp/src/components/meeting_settings/meeting_settings.jsx +++ b/webapp/src/components/meeting_settings/meeting_settings.jsx @@ -1,7 +1,7 @@ -import React from 'react'; import PropTypes from 'prop-types'; - +import React from 'react'; import {Modal} from 'react-bootstrap'; +import Select from 'react-select'; export default class MeetingSettingsModal extends React.PureComponent { static propTypes = { @@ -13,12 +13,81 @@ export default class MeetingSettingsModal extends React.PureComponent { saveMeetingSettings: PropTypes.func.isRequired, }; + options = [ + {value: 'Jan 2', label: 'month_day'}, + {value: '2 Jan', label: 'day_month'}, + {value: '1 2', label: 'month_day'}, + {value: '2 1', label: 'day_month'}, + {value: '2006 1 2', label: 'year_month_day'}, + ]; + + customStyles = { + menu: (provided) => { + return { + ...provided, + background: 'var(--center-channel-bg)', + color: 'var(--center-channel-color)', + }; + }, + option: (provided, {isFocused, isSelected}) => { + const bgColor = isFocused ? + { + backgroundColor: 'var(--button-bg)', + color: 'var(--button-color)', + } : + {}; + + return { + ...provided, + ...bgColor, + ':active': { + ...provided[':active'], + backgroundColor: isSelected ? + 'var(--button-bg)' : + 'var(--center-channel-bg)', + }, + }; + }, + menuList: (provided) => { + return ({ + ...provided, + height: 188, + color: 'var(--center-channel-color)', + }); + }, + control: (provided, state) => ({ + ...provided, + height: 34, + minHeight: 34, + border: '1px solid #ced4da', + boxShadow: state.isFocused ? 0 : '1px solid #ced4da', + '&:hover': { + border: '1px solid #ced4da', + }, + background: 'var(--center-channel-bg)', + }), + indicatorsContainer: (provided) => { + return ({ + ...provided, + height: 34, + }); + }, + singleValue: (provided, state) => { + const opacity = state.isDisabled ? 0.5 : 1; + const transition = 'opacity 300ms'; + const color = 'var(--center-channel-color)'; + const background = 'var(--center-channel-bg)'; + return {...provided, opacity, transition, color, background}; + }, + } + constructor(props) { super(props); this.state = { - hashtag: '{{Jan02}}', + hashtagPrefix: 'Prefix', weekdays: [1], + dateFormat: '1-2', // dateFormat will be an object type => { value: string, label: string } }; } @@ -28,9 +97,14 @@ export default class MeetingSettingsModal extends React.PureComponent { } if (this.props.meeting && this.props.meeting !== prevProps.meeting) { + const splitResult = this.props.meeting.hashtagFormat.split('{{');// we know, date Format is preceded by {{ + const hashtagPrefix = splitResult[0]; + const dateFormatValue = splitResult[1].substring(0, splitResult[1].length - 2).trim(); // remove trailing }} + const dateFormat = this.options.filter((i) => i.value === dateFormatValue)[0]; // extract value object // eslint-disable-next-line react/no-did-update-set-state this.setState({ - hashtag: this.props.meeting.hashtagFormat, + hashtagPrefix, + dateFormat, weekdays: this.props.meeting.schedule || [], }); } @@ -38,10 +112,14 @@ export default class MeetingSettingsModal extends React.PureComponent { handleHashtagChange = (e) => { this.setState({ - hashtag: e.target.value, + hashtagPrefix: e.target.value, }); } + handleDateFormat = (newValue) => { + this.setState({dateFormat: newValue}); + }; + handleCheckboxChanged = (e) => { const changeday = Number(e.target.value); let changedWeekdays = Object.assign([], this.state.weekdays); @@ -62,7 +140,7 @@ export default class MeetingSettingsModal extends React.PureComponent { onSave = () => { this.props.saveMeetingSettings({ channelId: this.props.channelId, - hashtagFormat: this.state.hashtag, + hashtagFormat: `${this.state.hashtagPrefix}{{${this.state.dateFormat.value}}}`, schedule: this.state.weekdays.sort(), }); @@ -108,7 +186,7 @@ export default class MeetingSettingsModal extends React.PureComponent { {'Channel Agenda Settings'} - +
- - -

{'Hashtag is formatted using the '} - {'Go time package.'} - {' Embed a date by surrounding what January 2, 2006 would look like with double curly braces, i.e. {{Jan02}}'} +

+
+ + +
+
+ +