diff --git includes/journal_patch_views_handler_field_module.inc includes/journal_patch_views_handler_field_module.inc
new file mode 100644
index 0000000..df1658f
--- /dev/null
+++ includes/journal_patch_views_handler_field_module.inc
@@ -0,0 +1,10 @@
+<?php
+// $Id$
+
+class journal_patch_views_handler_field_module extends views_handler_field {
+
+  function render($values) {
+    return theme('item_list', explode(',', $values->{$this->field_alias}), NULL, 'ul');
+  }
+
+}
diff --git includes/journal_patch_views_handler_field_status.inc includes/journal_patch_views_handler_field_status.inc
new file mode 100644
index 0000000..f296d75
--- /dev/null
+++ includes/journal_patch_views_handler_field_status.inc
@@ -0,0 +1,20 @@
+<?php
+// $Id$
+
+class journal_patch_views_handler_field_status extends views_handler_field {
+
+  var $patch_status;
+
+  function __construct() {
+    $this->patch_status = array(
+      'open' => t('Open'),
+      'fixed' => t('Fixed'),
+      "won't fix" => t("Won't fix"),
+    );
+  }
+
+  function render($values) {
+    return $this->patch_status[$values->{$this->field_alias}];
+  }
+
+}
diff --git includes/journal_patch_views_handler_filter_module.inc includes/journal_patch_views_handler_filter_module.inc
new file mode 100644
index 0000000..49e876f
--- /dev/null
+++ includes/journal_patch_views_handler_filter_module.inc
@@ -0,0 +1,17 @@
+<?php
+// $Id$
+
+class journal_patch_views_handler_filter_module extends views_handler_filter_in_operator {
+  function get_value_options() {
+    $this->value_options = module_list(FALSE, FALSE, TRUE);
+  }
+
+  function query() {
+    if (!empty($this->value)) {
+      $this->ensure_my_table();
+      $values = implode(',', $this->value);
+      $this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field = '%s'", $values);
+    }
+  }
+
+}
diff --git includes/journal_patch_views_handler_filter_status.inc includes/journal_patch_views_handler_filter_status.inc
new file mode 100644
index 0000000..505a289
--- /dev/null
+++ includes/journal_patch_views_handler_filter_status.inc
@@ -0,0 +1,17 @@
+<?php
+// $Id$
+
+class journal_patch_views_handler_filter_status extends views_handler_filter_in_operator {
+
+  function get_value_options() {
+    if (isset($this->value_options)) {
+      return;
+    }
+    $this->value_options = array(
+      'open' => t('open'),
+      'fixed' => t('fixed'),
+      "won't fix" => t("won't fix"),
+    );
+  }
+
+}
diff --git journal.module journal.module
index 2a09cc9..e1aac38 100644
--- journal.module
+++ journal.module
@@ -393,3 +393,9 @@ function journal_add_entry($description, $location) {
   db_query("INSERT INTO {journal} (uid, message, location, timestamp) VALUES (%d, '%s', '%s', %d)", $user->uid, $description, $location, time());
 }
 
+/**
+ * Implementation of hook_views_api().
+ */
+function journal_views_api() {
+  return array('api' => 2);
+}
diff --git journal.views.inc journal.views.inc
new file mode 100644
index 0000000..f0a5eb2
--- /dev/null
+++ journal.views.inc
@@ -0,0 +1,243 @@
+<?php
+// $Id$
+
+/**
+ * Implementation of hook_views_data().
+ */
+function journal_views_data() {
+
+  // Define the base group of this table. Fields that don't
+  // have a group defined will go into this field by default.
+  $data['journal']['table']['group']  = t('Journal entry');
+
+  // Advertise this table as a possible base table
+  $data['journal']['table']['base'] = array(
+    'field' => 'jid',
+    'title' => t('Journal entry'),
+    'help' => t('List journal entries.'),
+  );
+
+  // Join to 'users' as a base table.
+  $data['journal']['table']['join'] = array(
+    'user' => array(
+      'left_field' => 'uid',
+      'field' => 'uid',
+    ),
+  );
+
+  $data['journal']['jid'] = array(
+    'title' => t('ID'),
+    'help' => t('The primary identifier for a journal entry.'),
+    'field' => array(
+      'handler' => 'views_handler_field',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_numeric',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument',
+    ),
+  );
+
+  $data['journal']['message'] = array(
+    'title' => t('Message'),
+    'help' => t('The actual message of a journal entry.'),
+    'field' => array(
+      'handler' => 'views_handler_field',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+  );
+
+  $data['journal']['location'] = array(
+    'title' => t('Location'),
+    'help' => t('The internal Drupal path to the form a journal entry was entered in.'),
+    'field' => array(
+      'handler' => 'views_handler_field_url',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_string',
+    ),
+  );
+
+  $data['journal']['uid'] = array(
+    'title' => t('User'),
+    'help' => t('The user id of the author of a journal entry.'),
+    'relationship' => array(
+      'base' => 'users',
+      'base field' => 'uid',
+      'handler' => 'views_handler_relationship',
+      'label' => t('User'),
+    ),
+  );
+
+  $data['journal']['timestamp'] = array(
+    'title' => t('Post date'),
+    'help' => t('Date and time of when the journal entry was created.'),
+    'field' => array(
+      'handler' => 'views_handler_field_date',
+      'click sortable' => TRUE,
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort_date',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date',
+    ),
+  );
+
+  $data['journal_patch']['table']['group']  = t('Journal patch entry');
+
+  // Advertise this table as a possible base table
+  $data['journal_patch']['table']['base'] = array(
+    'field' => 'pid',
+    'title' => t('Journal patch entry'),
+    'help' => t('List journal patch entries.'),
+  );
+
+  $data['journal_patch']['pid'] = array(
+    'module' => 'journal',
+    'title' => t('ID'),
+    'help' => t('The primary identifier for a journal patch entry.'),
+    'field' => array(
+      'handler' => 'views_handler_field',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_numeric',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument',
+    ),
+  );
+
+  $data['journal_patch']['description'] = array(
+    'module' => 'journal',
+    'title' => t('Description'),
+    'help' => t('Description of a journal patch record.'),
+    'field' => array(
+      'handler' => 'views_handler_field',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+  );
+
+  $data['journal_patch']['url'] = array(
+    'module' => 'journal',
+    'title' => t('Url'),
+    'help' => t('URL of a related issue for a journal patch record.'),
+    'field' => array(
+      'handler' => 'views_handler_field_url',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+
+  $data['journal_patch']['uid'] = array(
+    'module' => 'journal',
+    'title' => t('User'),
+    'help' => t('The user id of the author of a journal patch entry.'),
+    'relationship' => array(
+      'base' => 'users',
+      'base field' => 'uid',
+      'handler' => 'views_handler_relationship',
+      'label' => t('User'),
+    ),
+  );
+
+  $data['journal_patch']['module'] = array(
+    'module' => 'journal',
+    'title' => t('Module'),
+    'help' => t('Affected module(s) of a journal patch record.'),
+    'field' => array(
+      'handler' => 'journal_patch_views_handler_field_module',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'journal_patch_views_handler_filter_module',
+    ),
+  );
+
+  $data['journal_patch']['status'] = array(
+    'module' => 'journal',
+    'title' => t('Status'),
+    'help' => t('Status of a journal patch record.'),
+    'field' => array(
+      'handler' => 'journal_patch_views_handler_field_status',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'journal_patch_views_handler_filter_status',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument',
+    ),
+  );
+
+  $data['journal_patch']['timestamp'] = array(
+    'module' => 'journal',
+    'title' => t('Post date'),
+    'help' => t('The UNIX timestamp when the journal patch record was created.'),
+    'field' => array(
+      'handler' => 'views_handler_field_date',
+      'click sortable' => TRUE,
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort_date',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date',
+    ),
+  );
+
+  return $data;
+}
+
+/**
+ * Implementation of hook_views_handlers().
+ */
+function journal_views_handlers() {
+  return array(
+    'info' => array(
+      'path' => drupal_get_path('module', 'journal') .'/includes',
+    ),
+    'handlers' => array(
+      'journal_patch_views_handler_field_module' => array(
+        'parent' => 'views_handler_field',
+      ),
+      'journal_patch_views_handler_filter_module' => array(
+        'parent' => 'views_handler_filter_in_operator',
+      ),
+      'journal_patch_views_handler_field_status' => array(
+        'parent' => 'views_handler_field',
+      ),
+      'journal_patch_views_handler_filter_status' => array(
+        'parent' => 'views_handler_filter_in_operator',
+      ),
+    ),
+  );
+}
