<div id="vue-loading">
  <i class="fas fa-circle-notch fa-spin fa-3x fa-fw"></i>
</div>

<div id="app" v-cloak>
  <div class="steps">
    <div class="number-box">1</div>
    <div class="header">
      Establish connection
      <span v-show="connected">
        <i class="session-status fas fa-link is-warning"></i>
      </span>
      <span v-show="!connected">
        <i class="session-status fas fa-unlink is-primary"></i>
      </span>
    </div>
  </div>
  <div id="tab-session">
    <form>
      <div v-if="showAdvancedSettings">
        <div class="field">
          <label class="label">Broker URL</label>
          <div class="control">
            <input class="input" type="text" v-model="tabs.session.form.url" />
          </div>
        </div>
        <div class="field">
          <label class="label">Client Username</label>
          <div class="control">
            <input class="input" type="text" v-model="tabs.session.form.userName" />
          </div>
        </div>
        <div class="field">
          <label class="label">Client Password</label>
          <div class="control">
            <input class="input" type="password" v-model="tabs.session.form.password" />
          </div>
        </div>
        <div class="field">
          <label class="label">Message VPN</label>
          <div class="control">
            <input class="input" type="text" v-model="tabs.session.form.vpnName" />
          </div>
        </div>
      </div>
      
      <div class='buttons'>
        <input class="button is-primary" 
               type="submit" 
               v-model="tabs.session.form.button.connect" 
               :disabled="session"
               @click.prevent="connect" 
               />
        <input class="button" 
               type="submit" 
               v-model="tabs.session.form.button.disconnect" 
               :disabled="!session" 
               @click.prevent="disconnect"
               />
        <input class="button" 
               type="submit" 
               v-model="tabs.session.form.button.advanced" 
               :disabled="false" 
               @click.prevent="toggleAdvancedSettings()"
               />
        <i class="fa fa-spinner fa-fw fa-spin" aria-hidden="true" v-if="sessionRequestPending"></i>
        

      </div>
    </form>
    
    <div class="status message is-primary" v-show="tabs.session.status.show">
      <div class="message-header">
        <p>Connect Status</p>
      </div>
      <div class="message-body">
        {{tabs.session.status.message}}
      </div>
    </div>
  </div>
  
  <div class="steps">
    <div class="number-box">4</div>
    <div class="header">Publish</div>
  </div>
  <div id="tab-publish">
    <form>
      <div class="field">
        <label class="label">Topic</label>
        <div class="control">
          <input class="input" type="text" v-model="tabs.publish.form.topic" />
        </div>
      </div>
      <div class="field">
        <label class="label">Message</label>
        <div class="control">
          <textarea class="textarea"
                    rows="3"
                    v-model="tabs.publish.form.message" 
                    placeholder="">
          </textarea>
        </div>
      </div>
      <div class="field">
        <div class="control">
          <label class="radio">
            <input type="radio" 
                   value="binaryAttachment"
                   v-model="tabs.publish.form.format">
            binary
          </label>
          <label class="radio">
            <input type="radio"
                   value="sdtText"
                   v-model="tabs.publish.form.format">
            text
          </label>
        </div>
      </div>
      <input class="button is-primary margin-top" 
             type="submit" 
             v-model="tabs.publish.form.button.publish" 
             :disabled="!connected" 
             @click.prevent="publish"
      />
    </form>
    <transition name="fade" mode="out-in">
      <div class="status message is-primary" 
           v-show="tabs.publish.status.show">
        <div class="message-header">
          <p>Publish Status</p>
        </div>
        <div class="message-body">
          {{tabs.publish.status.message}}
        </div>
      </div>
    </transition>
  </div>
</div>
$background-color:    #FFFFFF;
$banner-color:        #474747;
$border-top-color:    #606060;
$delete-tag-color:    #e0e0e0;
$field-shadow-color:  rgba(0, 0, 0, 0.15);
$format-select-color: #c0c0c0;
$label-color:         #595959;
$radio-color:         #7b7c7d;
$title-color:         #FFFFFF;

$font-stack:          'Rubik', sans-serif;
$font-weight-normal:  normal;

html {
  background-color: $background-color;
  height: 100%;
}

.title, 
.control, 
.field, 
.tabs, 
.input,
.textarea,
.radio {
  font-family: $font-stack;
  font-weight: $font-weight-normal;
}

.banner {
  margin: -2em -2em 0em -2em;
  padding: 1em 1em 0em 1em;
  background-color: $banner-color;  
}

.title {
  height: 50px;
  font-size: 1.8em;
  color: $title-color;
}

body {
  padding: 2em;
}

.label {
  color: $label-color;
  font-size: 0.8rem;
  font-weight: 400;
}

.input,
.textarea {
  font-size: 20px;
  font-weight: 300;
  box-shadow: 0 1px 1px $field-shadow-color;
}

label.radio {
  font-size: 15px;
  line-height: 25px;
  color: $radio-color;
}

[v-cloak] {
  display: none;
}

#vue-loading {
  display: block;
  position: absolute;
  left: 50%;
  top: 50%;
  width: 100%;
  height: 150px;
}

#tab-session, #tab-publish {
  margin-left: 50px;
}

.steps {
  display: flex;
  position: relative;
  margin: auto 0;
  height: 40px;
  margin-bottom: 5px;
  
  .number-box {
    width: 30px;
    height: 30px;
    color: white;
    background: #474747;
    text-align: center;
    margin: auto 20px auto 0;
    padding-top: 3px;
    border-radius: 5px;
  }
  .header {
    margin: auto 0;
    font-size: 18px;
    color: rgba(0, 0, 0, 0.65);
    font-weight: 500;
    flex: 1;
  }
}

form {
  .buttons {
    margin-top: 15px;
    margin-bottom: 5px !important;
    position: relative;
    .advanced {
      position: absolute;
      right: 0;
      color: #00ad93;
      bottom: 15px;
    }
    .fa-spinner {
      color: #00ad93;
    }
  }
  .is-primary {
    background: #00ad93 !important;
  }
  input.subscribe {
    font-size: 16px;
  }
}

.fade-enter, 
.fade-leave-active {
  opacity: 0;
}

.fade-enter-active, 
.fade-leave-active {
  transition: opacity .5s;
}

.status {
  margin-top: 2em;
}

.session-status {
  padding-right : 12px;
  font-size: 1em;
  &.fa-unlink {
    color: red;
  }
  &.fa-link {
    color: green;
  }
}

.tag.is-delete {
  background-color: $delete-tag-color;
}

.status {
  margin-top: 2em;
  .message-header {
    background: #00ad93 !important;
  }
}

.session-status {
  padding-right : 12px;
  font-size: 1em;
  &.fa-unlink {
    color: red;
  }
  &.fa-link {
    color: green;
  }
}

.messages {
  border-top: 1px solid $border-top-color;
  .message {
    margin-top: 1em;
    width: 100%;
  };
  .message-format {
    padding: 1em;
    background-color: $format-select-color;
  }
}

.tabs li.is-active a {
  border-bottom-color: #4a4a4a;
  color: #000;
}
View Compiled
const { 
  SolclientFactory, 
  SDTField,
  SDTFieldType,
  Session, 
  StatType,
  SessionEventCode,
  TransportProtocol 
} = solace;
const { 
  createSession, 
  createTopicDestination, 
  createMessage,
} = SolclientFactory;
const {
  getCurrentService
} = (SolaceCloud || {});

const app = new Vue({
  
  el: '#app',
  
  data: {
    tabs: {
      session: {
        active: true,
        form: {
          url: 'ws://localhost',
          userName: 'default',
          password: 'secret',
          vpnName: 'default',
          transportProtocol: TransportProtocol.HTTP_BINARY_STREAMING,
          button: {
            connect: 'Connect',
            disconnect: 'Disconnect',
            advanced: 'Advanced ...'
          }
        },
        status: {
          show: false,
          message: ''
        }
      },
      publish: {
        form: {
          topic: 'topic/try/me',
          message: 'Hello world!',
          format: 'binaryAttachment',
          button: {
            publish: 'Publish'
          }
        },
        status: {
          show: false,
          message: ''
        }
      }
    },
    
    connected: false,
    session: null,
    pendingSession: null,
    showAdvancedSettings: false
  },
  
  methods: {
    
    // Initialize the Solace API factory.
    init() {
      SolclientFactory.init({
        profile: SolclientFactory.profiles.version7
      });
      // If embedded in Solace Cloud (as a demo), ask the console for service credentials.
      getCurrentService && getCurrentService((r) => app.setSessionCredentials(r.data.service));
    },
    
    // Reset the application state.
    reset() {
      this.session.dispose();
      this.session = null;
      this.connected = false;
    },
    
    // Connect the session.
    connect() {
      if (this.session) this.reset();
      
      // Create a session with the given session properties
      try {
        this.session = createSession(this.tabs.session.form);
      } catch (ex) {
        this.setStatus('session', 'Error creating session: ' + ex.message);
        return;
      }
      
      this.session.on(SessionEventCode.UP_NOTICE, () => {
        this.sessionRequestCompleted();
        this.connected = true;
        this.setActiveTab('publish');
      });
      this.session.on(SessionEventCode.DISCONNECTED, () => {
        this.sessionRequestCompleted();
        this.reset();
      });
      this.session.on(SessionEventCode.DOWN_ERROR, (...args) => {
        console.log('DOWN_ERROR', args);
        this.setStatus('session', 'Session down with error ' + event);
        this.reset();
      });
 
      // Connect the session
      this.showSessionRequestPending();
      try {
        this.session.connect();      
      } catch (ex) {
        this.setStatus('session', 'Error connecting session: ' + ex.message);
        this.reset();
      }      
    },
    
    // Disconnect the session.
    disconnect() {
      if (!this.session) return;
      this.showSessionRequestPending();
      this.session.disconnect();
    },
    
    // Publish a message.
    // It is safe to publish arbitrary data, including text in the message's 
    // binaryAttachment, but using an SDT String field adds metadata to help 
    // identify the message content.
    publish() {
      const { session } = this;
      const { form } = this.tabs.publish;
      const message = createMessage();
      if (form.format == 'binaryAttachment') {
        message.setBinaryAttachment(form.message);
      } else {
        message.setSdtContainer(SDTField.create(SDTFieldType.STRING, form.message));
      }
      
      try {
        message.setDestination(createTopicDestination(form.topic));
        session.send(message);
      } catch (ex) {
        this.setStatus('publish', 'Publish error: ' + ex.message);      
        return;
      }
      this.setStatus('publish', session.getStat(StatType.TX_DIRECT_MSGS) + ' message(s) published');
    },
    
    // Pop up a status update.
    setStatus(type, message) {
      const statusNode = this.tabs[type].status;
      Object.assign(statusNode, {
        show: true,
        message
      });
      this.sessionRequestCompleted();
    },
    
    showSessionRequestPending() {
      this.sessionRequestPending = true;
    },
    
    sessionRequestCompleted() {
      this.sessionRequestPending = false;
    },
    
    // Set the active (displayed) UI tab.
    setActiveTab(selection) {
      Object.keys(this.tabs).forEach(tabName => {
        this.tabs[tabName].active = (tabName === selection);
      });
    },
    
    // toggle the advanced settings
    toggleAdvancedSettings() {
      this.showAdvancedSettings = !this.showAdvancedSettings;
      this.tabs.session.form.button.advanced = (!this.showAdvancedSettings) ? 'Advanced ...':'Less';
    },
    
    // Accept external session properties.
    setSessionCredentials(properties) {
      Object.assign(this.tabs.session.form, properties);
    }
    
  },
  
  mounted() {
    document.getElementById('vue-loading').remove();
    this.init();
  }
  
});
View Compiled

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css
  2. https://use.fontawesome.com/releases/v5.1.0/css/all.css

External JavaScript

  1. http://cdn.jsdelivr.net/npm/solclientjs
  2. https://storage.googleapis.com/solace-cloud-dx-static/api-console-bridge/0.0.1/solacecloud-getcurrentservice-0.0.1.js
  3. https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js