Friday, August 29, 2008

VisualForce App - Send Alert Button (Part 3) : Fleshing Out the Visualforce Page

This article describes a custom application that adds a "Send Alert" button on the Case Detail Record. The application basically does two things: (1) Sends an email status update to a distribution list of internal users, and (2) adds the status update as a Case Comment. This is the third in a series of articles describing how we implemented the feature, and pitfalls we ran into along the way.

Here is a code drop of the final Visualforce page behind the Send Alert button, which we previewed in Part 2:

WARNING: I'm finding that Blogger is a HORRIBLE medium for posting code like this, at least with the current template. I'm working on a website where I can post these code samples, and make it easier for readers to grab them. Hope to have that online in a week or two! In the meanwhile, my appologies for the ugly rendering in Blogger!


<!-- Alert Notification Wizard -->
<apex:page controller="SendAlertController">
<apex:sectionHeader title="Active Alert - Status Update" subtitle="Internal CPC Notification Only"/>
<apex:pageBlock >
This is an Internal (Cedar Point) <b>Sev {!Case.Priority} ALERT</b> Status Update for the <b>{!Account.Name}</b> Account Team.
</apex:PageBlock>
<apex:form >
<apex:pageBlock title="Current Status Update">
<apex:pageBlockButtons >
<apex:commandButton action="{!send}" value="Send Update"/>
<apex:commandButton action="{!sendfinal}" value="Send Final Update"/>
<apex:commandButton action="{!cancel}" value="Cancel"/>
</apex:pageBlockButtons>
<apex:pageBlockSection columns="1">
<apex:pageBlockSectionItem >
<apex:outputLabel value="Send To:" for="sendTo"/>
<apex:outputText value="Account Team Members plus {!sendtogroup} Group" id="sendTo"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
<apex:outputLabel value="Account Team Members:" for="teamMembers"/>
<apex:outputText value="{!teamMemberNames}" id="teamMembers"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
<apex:outputLabel value="Alert Group Members:" for="groupMembers"/>
<apex:outputText value="{!groupMemberNames}" id="groupMembers"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
<apex:outputLabel value="Additional To:" for="moreto"/>
<apex:inputTextarea id="moreTo" value="{!moreTo}" rows="1" cols="100"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
<apex:outputLabel value="Subject:" for="subject"/>
<apex:outputText id="subject" value="{!subject}"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
<apex:outputLabel value="Priority" for="priority"/>
<apex:outputField value="{!Case.Priority}" id="priority"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
<apex:outputLabel value="Case" for="caseNum"/>
<apex:outputLink value="/{!Case.Id}" id="caseNum">{!Case.CaseNumber}</apex:outputLink>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
<apex:outputLabel value="Description" for="caseDesc"/>
<apex:outputField value="{!Case.Subject}" id="caseDesc"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
<apex:outputLabel value="Switch" for="caseSwitch"/>
<apex:outputText value="{!SwitchName}" id="caseSwitch"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
<apex:outputLabel value="SW Rel" for="caseSwRel"/>
<apex:outputText value="{!SwitchRel}" id="caseSwRel"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
<apex:outputLabel value="Opened" for="caseCreatedDate"/>
<apex:outputField value="{!Case.CreatedDate}" id="caseCreatedDate"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
<apex:outputLabel value="Status Update" for="statusUpdate"/>
<apex:inputTextarea id="statusUpdate" value="{!comment.CommentBody}" rows="8" cols="100"/>
</apex:pageBlockSectionItem>
</apex:pageBlockSection>
</apex:PageBlock>
</apex:form>
<!-- <apex:detail /> -->
</apex:page>


That's the code, and here's what the final page looks like when rendered in a Visualforce page:

Thursday, August 28, 2008

Putting code in your Google Blog

We interrupt this Visualforce show-n-tell with a special announcement. One of my blog visitors, ELIT3, asked if I could post the code of my Visualforce pages, rather than screenshots. I tried to copy the code into the blog post, but when I viewed the posting, the code was all mangled. The browser had interpretted the Visualforce code as HTML, and disintegrated it.

I thought I could prevent that by just wrapping the code in <pre> </pre> tags, but that didn't seem to help. Today, I finally figured out that I need to wrap the code between some <code> </code> tags, but I still had to convert the "<", ">", other special characters.

I trolled around the web and found a couple sites to help with that, and thought I'd share. So if you're interested in posting code on your own blogs (and also for my own future reference, since I'm sure to forget), check these out!

My favorite is Elliot Swan's Postable site: http://www.elliotswan.com/postable/

I like the way it looks, and I love it's simplicity -- you just drop all your code into the text window:



Then, click the "Make it friendly" button. His browser app will replace all the "<", ">", and "&" symbols with the appropriate HTML translations.



Then, you simple wrap <code> </code> tags around your converted "HTML friendly" text, and wala! It's viewable in a Google Blog post (and can be copied by your readers!):


<!-- Alert Notification Wizard -->
<apex:page controller="SendAlertController">
<apex:sectionHeader title="Active Alert - Status Update" subtitle="Internal CPC Notification Only"/>
<apex:pageBlock >
This is an Internal (Cedar Point) <b>Sev {!Case.Priority} ALERT</b> Status Update for the <b>{!Account.Name}</b> Account Team.
</apex:PageBlock>
</apex:page>


Here's another site http://www.htmlconvert.net/ that goes one better, giving you an option to transform the text into standard HTML code with colorized tags:


<!-- Alert Notification Wizard -->
<apex:page controller="SendAlertController">
<apex:sectionHeader title="Active Alert - Status Update" subtitle="Internal CPC Notification Only"/>
<apex:pageBlock >
This is an Internal (Cedar Point) <b>Sev {!Case.Priority} ALERT</b> Status Update for the <b>{!Account.Name}</b> Account Team.
</apex:PageBlock>
</apex:page>

Cute!

Wednesday, August 27, 2008

VisualForce App - Send Alert Button (Part 2) : How do I make a Visualforce Page, anyway?

This article describes a custom application that adds a "Send Alert" button on the Case Detail Record. The application basically does two things: (1) Sends an email status update to a distribution list of internal users, and (2) adds the status update as a Case Comment. This is the second in a series of articles describing how we implemented the feature, and pitfalls we ran into along the way.

In yesterday's blog, I described the basics of what we wanted to accomplish with the proposed "Send Alert" button. Today, I'll retrace our first steps, showing how we first "dipped our toes" in the Visualforce waters.

Ok ... How Do I Make a Visualforce Page, Anyway?

My first glimpse into Visualforce was during Marc Benioff's keynote at Dreamforce 2007. I'll confess to you right up front, the developers make this look EASY, but it took a little bit of stumbling before I made my first Visualforce page. Not to worry, it gets easier with practice!

At Dreamforce 2007, I had jotted down notes --pages of notes, actually -- and I flipped through them with enthusiasm. Enthusiasm turned to confusion, which turned to despair. I realized I had no idea where to begin. Apparently I'd left out some notes for making a Visualforce page.

I hit the Developer's Wiki: http://wiki.apexdevnet.com/index.php/Apex_and_Visualforce. If you've never been here, visit now!

There are a ton of videos, user guides, and "getting started" presentations for the aspiring Apex / Visualforce developer. I spent a good chunk of the day just watching the videos, and perusing the developer's guide. Eventually, I realized I was just procrastinating, and it was time to dig in.

I followed a step that I saw Ron Hess do in one of the video presentations; I typed the following URL into my browser:

https://na3.salesforce.com/apex/SendAlert

(NOTE: If you're crazy enough to be following along, be sure that you substitute "na3" for the correct pod on which your instance of Salesforce runs, typically na1, na2, na3, na4, na5, etc.)

That's the simpler method of creating a new Visualforce page ... just add "/apex/page_name" to the end of your Salesforce pod name. Because the Visualforce page does not yet exist, the platform prompts you to create a new page.



Oooh, cool! I've played with plenty of HTML, so I could immediately see what was happening here. I resisted the urge to create my first Visualforce "Hello World" page, and plowed on with the application.


I copied the browser URL ("https://na3.salesforce.com/apex/SendAlert") to my clipboard, and then created a custom button for the Case object.

If you're following along at home (or work, or whatever):



  1. Click Setup --> Customize --> Cases --> Buttons and links

  2. Click NEW in the "Custom Buttons and Links" section
    Make your custom button look like this.

Note that in the content section of the Browser, I've pasted the clipboard content, and then added "?={!Case.Id}" to the end. Whenever this "Send Alert" button is evoked from a Case Detail Page, it will open our new VisualForce page, with the current case record in "focus".





I added the custom button to our Case page layout:



  1. Click Setup --> Customize --> Cases --> Page Layouts

  2. Edit the appropriate "Case Layout"

  3. Click the "Detail Page Buttons" component, and then click "Edit Properties"

  4. Move the "Send Alert" button from the "Available Buttons" list to the "Selected Buttons" list.

So there's our button, and now we have a Case detail record in focus when we open the Visualforce Page. I modified the Visualforce page with some basic headers:


Pretty cool, pretty easy! Tomorrow we'll work on the input text box, and the rest of the Visualforce page.

Tuesday, August 26, 2008

VisualForce App - Send Alert Button (Part 1)

This article describes a custom application that adds a "Send Alert" button on the Case Detail Record. The application basically does two things: (1) Sends an email status update to a distribution list of internal users, and (2) adds the status update as a Case Comment. This is the first in a series of articles describing how we implemented the feature, and pitfalls we ran into along the way.


BACKGROUND: At the company where I work, several cross-functional teams snap into action when a Sev-1 (Critical Issue), Sev-2 (Major Issue) or Sev-3 (Operational Issue) is reported into Technical Support by one of our customers. In accordance with our internal business policies, Tech Support must notify these cross-functional teams via email, and provide periodic status updates as the Case is being worked.

The teams include members from Engineering, Technical Support, and of course, the Sales/Account Team. All cross-functional team members monitor the updates via Blackberry, and respond appropriately. For example, Engineering dispatches a SWAT team to assist Tech Support with issue resolution. At the same time, the Sales/Account team contact Customer management, providing a proactive message ("we're on it") and ongoing status updates.


PROBLEM WE WERE TRYING TO SOLVE: There were two problems we observed after this procedure was put in place.

(1) Status Updates Were Not Being Added to the Case: While our technical team was very good about sending the internal email status updates, they were inconsistent in the practice of copying these updates into the Case. The directors and managers made request after request for these updates to be added as a Case comment -- but the discipline never came. We decided that if we gave Tech Support a method for entering the status updates within Salesforce.com, we could have the platform send out the email status update, and also store the update as a Case Comment automatically.

(2) Targeting the Update to the Right Audience: The distribution list to which these email status updates were sent changes frequently, because our Account Teams shift dynamically, depending on the project demands of our customer base. The distribution list for the status updates also changed depending on the Customer account, and the severity (Priority) of the case. It was difficult for Tech Support to keep tabs on these ever-changing distribution lists. We wanted to make this completely transparent to the Technical Team -- they just had to create a status update, and the SFDC platform would distribute it to the correct distribution list.


HOW WE DID IT: We added a custom "Send Alert" button, a Visualforce page, and some Apex code to the Case detail record which basically does the following:

1.) Displays some basic template of summary information from the case, which will be included in the email status update.
2.) Provides a blank text window, where the user can post the current status update.
3.) Packages all the summary info and status update into an email message, and sends it to the appropriate Account Team, as well as the cross-functional team members.
4.) Posts the status update as a new case comment.


Okay, that's the background. Tomorrow, we'll show how we went about creating the Visualforce portion of this application. Stay tuned!

Sunday, August 24, 2008

LinkedIn Let's the Cat out of the Bag

Most of my professional life, I've worked for small start ups (50-150 employees). Just as with larger corporations, start-up companies go through turbulent years and may experience lay-offs. I've weathered many lay-offs at various companies that I've worked for, although in recent years, I've found that the language has changed. They are no longer lay-offs, but RIFs (Reduction in Force).

It used to be that whenever a Lay-off would come, surviving employees would be called together, either in small groups or in a larger "all-hands" meeting. The executive staff would sometimes describe the reasons for the lay-off ... err, RIF, explain why it was necessary, how we would all need to pull together, work harder with less -- you know the drill.

Invariably, Human Resources would step up at the end, and remind all employees that they must not discuss the RIF with anyone outside the company. If any employees were contacted by outside recruiting firms or companies looking for the names of "termed employees", the callers should be immediately referred to HR.

I'm not sure how effectively that worked in the old days, but I know it's not working very effectively in our Web 2.0 world today. Here's a telephone conversation I had with a former business colleague, who still works at the company I left several years ago.

ME: "So you guys got some big lay-offs recently, huh?"

HER: "Oh my god ... how did you know? No one outside the company is supposed to know. They just announced it! They're still calling people down for their exit interviews."

I shared a couple names of folks I thought who might be on the "termed employee" list.

HER: "Ok, now, you're freaking me out. I just saw him walk by with HR and an empty cardboard box. They were going down to clear out his office. How did you know?"

ME: "LinkedIn."

HER: "Huh?"

ME: "LinkedIn. I was just scrolling through the Network Updates of my LinkedIn connections, and I saw a whole bunch of recommendations being written up by folks who work there."

I've commented about LinkedIn before on this blog. LinkedIn is a social networking group focused on "connecting academic and business colleagues together, even as they change jobs and careers". One of the neat features of LinkedIn is that once you've added a colleague as being "connected / assocaited" to yourself, you can watch updates that they make to their resume, updates they make to projects that they are currently working on, and in this case, recommendations that they are either writing for other LinkedIn users, or even recommendations that have been written for them (by other LinkedIn users).

It wasn't difficult to see that there was a flurry of recommendation letters being written for and by employees from my old stomping grounds. Occasionally someone might write a recommendation letter for someone without prompting, but this level of activity usually indicates that lay-offs are in process, a merger / acquisition is coming down, or something is panicing the work force -- such that they are all looking to get there resumes updated, and their LinkedIn network updated on their changing work status.

My friend survived the lay- ... RIF, and I'm glad. And she later told me that they get the same monologue from HR, to not share the company job changes outside of the company. But by then, LinkedIn had already let the proverbial cat out of the bag.

Monday, August 18, 2008

Back to the Grind

I like my job, I really do. That seems to come as a great surprise to a great many people, but I honestly love my career in high tech.

I like my vacations, too. I'm just back from a week at the beach, and as always, it's taking a while to slip it in gear. While on vacation, I'm on a complete media and technology black-out. No iPod, No WiFi, no laptop, no Blackberry. There's a TV at the summer beach cottage (which we rent from my father), but I don't even turn that on. World events come to us by way of a curious, low-tech marvel called a "newspaper" -- which I fetch each morning by walking a half-mile (round trip) to a nearby roadside market.

At the beach, I totally immerse in being a kid, with my kids: building sandcastles on the beach, playing bocce, tossing frisbees, and surfing. I do a lot of reading at the beach, more than I do at home, but not from a Kindle. Instead, I haul these heavy, clunky things called "books" in my beach bag. Unlike the online media that I read all through the year, these often have nothing to do with high-tech.

This week I read The Good Guy (Dean Koontz), You've Been Warned (James Paterson), and Duma Key (Stephen King). These aren't book titles that I, necessarily, would have selected from a bookstore -- but they were all hard-cover books that had been left on the cottage book shelves by previous tenants. I did enjoy the first two, I found the Stephen King book to drag on too much.

I love the beach, I love the "escape", but it's really hard to jump back to work. Keep in mind my opening to this blog post -- I love my job, I love the work that I do -- but after a full week of being completely unplugged, it's surprising to me how hard it is to get back to work.

Examples:

- When the alarm clock sounded, I had no idea what it was. The "beep, beep" of the alarm was associated as a truck, backing up, outside my window. I was getting extremely annoyed at the truck driver, who was taking so long to back-up, until I realized that it was an alarm clock.

- Leaving the house this morning, I tried to get on my bicycle, rather than in my commuter car. I had strattled the bike before remembering that I don't work close enough for cycling to work (I wish!). I was still in beach mode, heading out for a morning bike ride.

- My computer is an alien thing to me. I couldn't even turn it on. Instead, I made office visits to the "usual suspects", to see what happened at the office the past week and what they felt needed my urgent attention.

I worked from pen and paper for a good chunk of the morning, and I'm slowing booting up. This blog gets the first attention of the day, but there is a pile of 705 email messages waiting for me next. Back to the grind ...